actors moved from stdlib to example
This commit is contained in:
+62
-78
@@ -76,16 +76,7 @@
|
|||||||
<file leaf-file-name="Actors.kt" pinned="false" current="true" current-in-tab="true">
|
<file leaf-file-name="Actors.kt" pinned="false" current="true" current-in-tab="true">
|
||||||
<entry file="file://$PROJECT_DIR$/src/org/jetbrains/examples/actors/Actors.kt">
|
<entry file="file://$PROJECT_DIR$/src/org/jetbrains/examples/actors/Actors.kt">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state line="2" column="37" selection-start="62" selection-end="62" vertical-scroll-proportion="-0.550152">
|
<state line="130" column="0" selection-start="4054" selection-end="4054" vertical-scroll-proportion="0.9736434">
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file leaf-file-name="Actors.kt" pinned="false" current="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../stdlib/ktSrc/concurrent/Actors.kt">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state line="2" column="43" selection-start="47" selection-end="47" vertical-scroll-proportion="0.0">
|
|
||||||
<folding />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
@@ -179,8 +170,8 @@
|
|||||||
<option value="$PROJECT_DIR$/../../stdlib/ktSrc/JavaLang.kt" />
|
<option value="$PROJECT_DIR$/../../stdlib/ktSrc/JavaLang.kt" />
|
||||||
<option value="$PROJECT_DIR$/../../stdlib/ktSrc/concurrent/Thread.kt" />
|
<option value="$PROJECT_DIR$/../../stdlib/ktSrc/concurrent/Thread.kt" />
|
||||||
<option value="$PROJECT_DIR$/src/org/jetbrains/examples/actors/Sample.kt" />
|
<option value="$PROJECT_DIR$/src/org/jetbrains/examples/actors/Sample.kt" />
|
||||||
<option value="$PROJECT_DIR$/src/org/jetbrains/examples/actors/Actors.kt" />
|
|
||||||
<option value="$PROJECT_DIR$/../../stdlib/ktSrc/concurrent/Actors.kt" />
|
<option value="$PROJECT_DIR$/../../stdlib/ktSrc/concurrent/Actors.kt" />
|
||||||
|
<option value="$PROJECT_DIR$/src/org/jetbrains/examples/actors/Actors.kt" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
@@ -216,26 +207,6 @@
|
|||||||
<sortByType />
|
<sortByType />
|
||||||
</navigator>
|
</navigator>
|
||||||
<panes>
|
<panes>
|
||||||
<pane id="PackagesPane">
|
|
||||||
<subPane>
|
|
||||||
<PATH>
|
|
||||||
<PATH_ELEMENT>
|
|
||||||
<option name="myItemId" value="example-actors" />
|
|
||||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PackageViewProjectNode" />
|
|
||||||
</PATH_ELEMENT>
|
|
||||||
</PATH>
|
|
||||||
</subPane>
|
|
||||||
</pane>
|
|
||||||
<pane id="Scope">
|
|
||||||
<subPane subId="Project Files">
|
|
||||||
<PATH>
|
|
||||||
<PATH_ELEMENT USER_OBJECT="Root">
|
|
||||||
<option name="myItemId" value="" />
|
|
||||||
<option name="myItemType" value="" />
|
|
||||||
</PATH_ELEMENT>
|
|
||||||
</PATH>
|
|
||||||
</subPane>
|
|
||||||
</pane>
|
|
||||||
<pane id="ProjectPane">
|
<pane id="ProjectPane">
|
||||||
<subPane>
|
<subPane>
|
||||||
<PATH>
|
<PATH>
|
||||||
@@ -348,20 +319,40 @@
|
|||||||
</PATH>
|
</PATH>
|
||||||
</subPane>
|
</subPane>
|
||||||
</pane>
|
</pane>
|
||||||
|
<pane id="PackagesPane">
|
||||||
|
<subPane>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="example-actors" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PackageViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
|
<pane id="Scope">
|
||||||
|
<subPane subId="Project Files">
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT USER_OBJECT="Root">
|
||||||
|
<option name="myItemId" value="" />
|
||||||
|
<option name="myItemType" value="" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
</panes>
|
</panes>
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">
|
<component name="PropertiesComponent">
|
||||||
<property name="project.structure.last.edited" value="Modules" />
|
|
||||||
<property name="GoToFile.includeJavaFiles" value="false" />
|
<property name="GoToFile.includeJavaFiles" value="false" />
|
||||||
<property name="project.structure.proportion" value="0.0" />
|
<property name="project.structure.last.edited" value="Modules" />
|
||||||
<property name="GoToClass.toSaveIncludeLibraries" value="false" />
|
<property name="GoToClass.toSaveIncludeLibraries" value="false" />
|
||||||
<property name="recentsLimit" value="5" />
|
<property name="project.structure.proportion" value="0.0" />
|
||||||
<property name="MemberChooser.sorted" value="false" />
|
<property name="MemberChooser.sorted" value="false" />
|
||||||
|
<property name="recentsLimit" value="5" />
|
||||||
<property name="MemberChooser.showClasses" value="true" />
|
<property name="MemberChooser.showClasses" value="true" />
|
||||||
<property name="project.structure.side.proportion" value="0.0" />
|
|
||||||
<property name="GoToClass.includeLibraries" value="false" />
|
<property name="GoToClass.includeLibraries" value="false" />
|
||||||
<property name="dynamic.classpath" value="false" />
|
<property name="project.structure.side.proportion" value="0.0" />
|
||||||
<property name="MemberChooser.copyJavadoc" value="false" />
|
<property name="MemberChooser.copyJavadoc" value="false" />
|
||||||
|
<property name="dynamic.classpath" value="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="RecentsManager">
|
<component name="RecentsManager">
|
||||||
<key name="MoveFile.RECENT_KEYS">
|
<key name="MoveFile.RECENT_KEYS">
|
||||||
@@ -429,24 +420,6 @@
|
|||||||
<option name="Maven.BeforeRunTask" enabled="false" />
|
<option name="Maven.BeforeRunTask" enabled="false" />
|
||||||
</method>
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration default="true" type="Applet" factoryName="Applet">
|
|
||||||
<module name="" />
|
|
||||||
<option name="MAIN_CLASS_NAME" />
|
|
||||||
<option name="HTML_FILE_NAME" />
|
|
||||||
<option name="HTML_USED" value="false" />
|
|
||||||
<option name="WIDTH" value="400" />
|
|
||||||
<option name="HEIGHT" value="300" />
|
|
||||||
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
|
|
||||||
<option name="VM_PARAMETERS" />
|
|
||||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
|
||||||
<option name="ALTERNATIVE_JRE_PATH" />
|
|
||||||
<method>
|
|
||||||
<option name="AntTarget" enabled="false" />
|
|
||||||
<option name="BuildArtifacts" enabled="false" />
|
|
||||||
<option name="Make" enabled="true" />
|
|
||||||
<option name="Maven.BeforeRunTask" enabled="false" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
<configuration default="true" type="TestNG" factoryName="TestNG">
|
<configuration default="true" type="TestNG" factoryName="TestNG">
|
||||||
<module name="" />
|
<module name="" />
|
||||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||||
@@ -479,6 +452,24 @@
|
|||||||
<option name="Maven.BeforeRunTask" enabled="false" />
|
<option name="Maven.BeforeRunTask" enabled="false" />
|
||||||
</method>
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
<configuration default="true" type="Applet" factoryName="Applet">
|
||||||
|
<module name="" />
|
||||||
|
<option name="MAIN_CLASS_NAME" />
|
||||||
|
<option name="HTML_FILE_NAME" />
|
||||||
|
<option name="HTML_USED" value="false" />
|
||||||
|
<option name="WIDTH" value="400" />
|
||||||
|
<option name="HEIGHT" value="300" />
|
||||||
|
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
|
||||||
|
<option name="VM_PARAMETERS" />
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH" />
|
||||||
|
<method>
|
||||||
|
<option name="AntTarget" enabled="false" />
|
||||||
|
<option name="BuildArtifacts" enabled="false" />
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
<option name="Maven.BeforeRunTask" enabled="false" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
<configuration default="true" type="Application" factoryName="Application">
|
<configuration default="true" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" />
|
<option name="MAIN_CLASS_NAME" />
|
||||||
<option name="VM_PARAMETERS" />
|
<option name="VM_PARAMETERS" />
|
||||||
@@ -560,7 +551,7 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="ToolWindowManager">
|
<component name="ToolWindowManager">
|
||||||
<frame x="1" y="22" width="1411" height="826" extended-state="0" />
|
<frame x="1" y="22" width="1411" height="826" extended-state="0" />
|
||||||
<editor active="false" />
|
<editor active="true" />
|
||||||
<layout>
|
<layout>
|
||||||
<window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
<window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||||
<window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
<window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||||
@@ -576,7 +567,7 @@
|
|||||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3294204" sideWeight="0.21782178" order="1" side_tool="true" content_ui="tabs" />
|
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3294204" sideWeight="0.21782178" order="1" side_tool="true" content_ui="tabs" />
|
||||||
<window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
<window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||||
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
<window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.3294204" sideWeight="0.67043847" order="0" side_tool="false" content_ui="combo" />
|
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.3294204" sideWeight="0.67043847" order="0" side_tool="false" content_ui="combo" />
|
||||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32956153" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32956153" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||||
<window_info id="ResolveWindow" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3294204" sideWeight="0.67043847" order="3" side_tool="false" content_ui="tabs" />
|
<window_info id="ResolveWindow" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3294204" sideWeight="0.67043847" order="3" side_tool="false" content_ui="tabs" />
|
||||||
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||||
@@ -673,6 +664,20 @@
|
|||||||
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
|
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/../../stdlib/ktSrc/JavaCollections.kt">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0">
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/../../stdlib/ktSrc/JavaUtil.kt">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0">
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/../../stdlib/ktSrc/concurrent/FunctionalQueue.kt">
|
<entry file="file://$PROJECT_DIR$/../../stdlib/ktSrc/concurrent/FunctionalQueue.kt">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
|
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
|
||||||
@@ -703,30 +708,9 @@
|
|||||||
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
|
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/../../stdlib/ktSrc/JavaCollections.kt">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0">
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../stdlib/ktSrc/JavaUtil.kt">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0">
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../stdlib/ktSrc/concurrent/Actors.kt">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state line="2" column="43" selection-start="47" selection-end="47" vertical-scroll-proportion="0.0">
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/org/jetbrains/examples/actors/Actors.kt">
|
<entry file="file://$PROJECT_DIR$/src/org/jetbrains/examples/actors/Actors.kt">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state line="2" column="37" selection-start="62" selection-end="62" vertical-scroll-proportion="-0.550152">
|
<state line="130" column="0" selection-start="4054" selection-end="4054" vertical-scroll-proportion="0.9736434">
|
||||||
<folding />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
|
|||||||
@@ -7,6 +7,127 @@ import java.util.concurrent.*
|
|||||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
|
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
|
/*
|
||||||
|
Message handling class which process only one message at any given moment
|
||||||
|
|
||||||
|
Three main ways to use it
|
||||||
|
- post and forget
|
||||||
|
- post and await result
|
||||||
|
- post and assign callback to be called when message processed
|
||||||
|
*/
|
||||||
|
abstract class Actor(protected val executor: Executor) {
|
||||||
|
// we can not do it private or protected
|
||||||
|
// otherwise updater defined in class object will not be able to access it
|
||||||
|
volatile var queue : FunctionalQueue<Any> = emptyQueue
|
||||||
|
|
||||||
|
/*
|
||||||
|
Handle message and return result
|
||||||
|
This method guaranteed to be executed only one per object at any given time
|
||||||
|
*/
|
||||||
|
protected abstract fun onMessage(message: Any) : Any?
|
||||||
|
|
||||||
|
/*
|
||||||
|
Post message to the actor.
|
||||||
|
The method returns immediately and the message itself will be processed later
|
||||||
|
*/
|
||||||
|
fun post(message: Any) {
|
||||||
|
while(true) {
|
||||||
|
val q = queue
|
||||||
|
if(q.empty) {
|
||||||
|
if(queueUpdater.compareAndSet(this, q, busyEmptyQueue)) {
|
||||||
|
executor.execute { process(message) }
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val newQueue = (if(q == busyEmptyQueue) emptyQueue else q) add message
|
||||||
|
if(queueUpdater.compareAndSet(this, q, newQueue)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Post message to the actor and schedule callback to be executed on given executor when message processed
|
||||||
|
*/
|
||||||
|
fun post(message: Any, executor: Executor = this.executor, callback: (Any?)->Unit) =
|
||||||
|
post(Callback(message, executor, callback))
|
||||||
|
|
||||||
|
/*
|
||||||
|
Send message to the actor and await result
|
||||||
|
*/
|
||||||
|
fun send(message: Any) : Any? {
|
||||||
|
val request = Request(message)
|
||||||
|
post(request)
|
||||||
|
request.await()
|
||||||
|
return request.result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nextMessage() {
|
||||||
|
while(true) {
|
||||||
|
val q = queue
|
||||||
|
if(q == busyEmptyQueue) {
|
||||||
|
if(queueUpdater.compareAndSet(this, busyEmptyQueue, emptyQueue)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val removed = q.removeFirst()
|
||||||
|
val newQueue = if(removed._2.empty) busyEmptyQueue else removed._2
|
||||||
|
if(queueUpdater.compareAndSet(this, q, newQueue)) {
|
||||||
|
executor.execute { process(removed._1) }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun process(message: Any) {
|
||||||
|
when(message) {
|
||||||
|
is Request -> {
|
||||||
|
message.result = onMessage(message.message)
|
||||||
|
message.countDown()
|
||||||
|
}
|
||||||
|
is Callback -> {
|
||||||
|
val result = onMessage(message.message)
|
||||||
|
message.executor execute {
|
||||||
|
val callback = message.callback;
|
||||||
|
callback(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> onMessage(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
nextMessage()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create actor on the same executor
|
||||||
|
*/
|
||||||
|
fun actor(handler: (Any)->Any?) = executor.actor(handler)
|
||||||
|
|
||||||
|
class object {
|
||||||
|
val queueUpdater = AtomicReferenceFieldUpdater.newUpdater(typeinfo<Actor>.javaClassForType,typeinfo<FunctionalQueue<Any>>().javaClassForType, "queue").sure()
|
||||||
|
val emptyQueue = FunctionalQueue<Any>()
|
||||||
|
val busyEmptyQueue = FunctionalQueue<Any>() add "busy empty queue"
|
||||||
|
|
||||||
|
class Request(val message: Any) : java.util.concurrent.CountDownLatch(1) {
|
||||||
|
var result: Any? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
class Callback(val message: Any, val executor: Executor, val callback: (Any?) -> Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Executor.actor(handler: (Any)->Any?) : Actor = object: Actor(this) {
|
||||||
|
override fun onMessage(message: Any) {
|
||||||
|
handler(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun singleThreadActor(handler: (Any)->Any?) : Actor = Executors.newSingleThreadExecutor().sure().actor(handler)
|
||||||
|
|
||||||
class App() : Actor(Executors.newFixedThreadPool(10).sure()) {
|
class App() : Actor(Executors.newFixedThreadPool(10).sure()) {
|
||||||
private val logger = executor.actor { message ->
|
private val logger = executor.actor { message ->
|
||||||
println("${Date()}:\t\t$message")
|
println("${Date()}:\t\t$message")
|
||||||
|
|||||||
@@ -1,130 +0,0 @@
|
|||||||
package std.concurrent
|
|
||||||
|
|
||||||
import std.concurrent.*
|
|
||||||
import std.util.*
|
|
||||||
|
|
||||||
import java.util.concurrent.*
|
|
||||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
|
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
/*
|
|
||||||
Message handling class which process only one message at any given moment
|
|
||||||
|
|
||||||
Three main ways to use it
|
|
||||||
- post and forget
|
|
||||||
- post and await result
|
|
||||||
- post and assign callback when message processed
|
|
||||||
*/
|
|
||||||
abstract class Actor(protected val executor: Executor) {
|
|
||||||
// we can not do it private or protected
|
|
||||||
// otherwise updater defined in class object will not be able to access it
|
|
||||||
volatile var queue : FunctionalQueue<Any> = emptyQueue
|
|
||||||
|
|
||||||
/*
|
|
||||||
Handle message and return result
|
|
||||||
This method guaranteed to be executed only one per object at any given time
|
|
||||||
*/
|
|
||||||
protected abstract fun onMessage(message: Any) : Any?
|
|
||||||
|
|
||||||
/*
|
|
||||||
Post message to the actor.
|
|
||||||
The method returns immediately and the message itself will be processed later
|
|
||||||
*/
|
|
||||||
fun post(message: Any) {
|
|
||||||
while(true) {
|
|
||||||
val q = queue
|
|
||||||
if(q.empty) {
|
|
||||||
if(queueUpdater.compareAndSet(this, q, busyEmptyQueue)) {
|
|
||||||
executor.execute { process(message) }
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val newQueue = (if(q == busyEmptyQueue) emptyQueue else q) add message
|
|
||||||
if(queueUpdater.compareAndSet(this, q, newQueue)) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Post message to the actor and schedule callback to be executed on given executor when message processed
|
|
||||||
*/
|
|
||||||
fun post(message: Any, executor: Executor = this.executor, callback: (Any?)->Unit) =
|
|
||||||
post(Callback(message, executor, callback))
|
|
||||||
|
|
||||||
/*
|
|
||||||
Send message to the actor and await result
|
|
||||||
*/
|
|
||||||
fun send(message: Any) : Any? {
|
|
||||||
val request = Request(message)
|
|
||||||
post(request)
|
|
||||||
request.await()
|
|
||||||
return request.result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun nextMessage() {
|
|
||||||
while(true) {
|
|
||||||
val q = queue
|
|
||||||
if(q == busyEmptyQueue) {
|
|
||||||
if(queueUpdater.compareAndSet(this, busyEmptyQueue, emptyQueue)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val removed = q.removeFirst()
|
|
||||||
val newQueue = if(removed._2.empty) busyEmptyQueue else removed._2
|
|
||||||
if(queueUpdater.compareAndSet(this, q, newQueue)) {
|
|
||||||
executor.execute { process(removed._1) }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun process(message: Any) {
|
|
||||||
when(message) {
|
|
||||||
is Request -> {
|
|
||||||
message.result = onMessage(message.message)
|
|
||||||
message.countDown()
|
|
||||||
}
|
|
||||||
is Callback -> {
|
|
||||||
val result = onMessage(message.message)
|
|
||||||
message.executor execute {
|
|
||||||
val callback = message.callback;
|
|
||||||
callback(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> onMessage(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
nextMessage()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Create actor on the same executor
|
|
||||||
*/
|
|
||||||
fun actor(handler: (Any)->Any?) = executor.actor(handler)
|
|
||||||
|
|
||||||
class object {
|
|
||||||
val queueUpdater = AtomicReferenceFieldUpdater.newUpdater(typeinfo<Actor>.javaClassForType,typeinfo<FunctionalQueue<Any>>().javaClassForType, "queue").sure()
|
|
||||||
val emptyQueue = FunctionalQueue<Any>()
|
|
||||||
val busyEmptyQueue = FunctionalQueue<Any>() add "busy empty queue"
|
|
||||||
|
|
||||||
class Request(val message: Any) : java.util.concurrent.CountDownLatch(1) {
|
|
||||||
var result: Any? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
class Callback(val message: Any, val executor: Executor, val callback: (Any?) -> Unit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Executor.actor(handler: (Any)->Any?) : Actor = object: Actor(this) {
|
|
||||||
override fun onMessage(message: Any) {
|
|
||||||
handler(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun singleThreadActor(handler: (Any)->Any?) : Actor = Executors.newSingleThreadExecutor().sure().actor(handler)
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user