FastTracks / TheAkkaWay

Akka Chinese Book / What should be included in it?
Apache License 2.0
19 stars 3 forks source link

Actor在不同线程之间调度执行业务时,Actor内部Object的对象属性内存可见性问题 #27

Open mackstone opened 7 years ago

mackstone commented 7 years ago

“在时刻M1,Actor A1被线程T1所执行处理消息m0,内部状态S发生改变,假设S=1; 在时刻M2, Actor A1被线程T2所执行去处理消息m1, 此刻Actor A1必然能观察到S==1,而不会出现S的值在内存中不可见的问题。” 问题: 当前的S可以是对象吗?如果是对象那么Actor在AKKA中是如何来实现共享内存对象的可见性问题?

He-Pin commented 7 years ago

首先在同一个时刻,只会有一个线程执行这个Actor,所以当Actor继续被调度的时候,肯定可以观测到最新的状态哈. 因为这个状态属于这个Actor,而不属于某个线程.

状态可以是任何东西哈.

mackstone commented 7 years ago

属于Actor不属于线程这个我没理解过来,可以说的更详细点吗?有相关知识点的资料吗?谢谢

He-Pin commented 7 years ago

Erlang 资料请看Erlang

就是说这个是ActorCell的一个字段而已

He-Pin commented 7 years ago

Refs

kerr我理解你说的意思了,actor内部状态的改变跟线程没关系,只跟actor自身有关;只要我不把这个内部状态暴露出去,那么对actor来说,怎么改变这个状态对actor自身来说都是可见的

mackstone commented 7 years ago

在issues中提及的问题: “在时刻M1,Actor A1被线程T1所执行处理消息m0,内部状态S发生改变,假设S=1; 在时刻M2, Actor A1被线程T2所执行去处理消息m1, 此刻Actor A1必然能观察到S==1,而不会出现S的值在内存中不可见的问 题。” 在AKKA中的Actor模型能保证可见性的实现原理如下: 这个可见性是基于JMM 中happens-before规则实现(基于如下三种happens-before规则)的: 1.程序顺序规则:一个线程中每个操作,happens-before于该线程中的任意后续操作。 2.volatile变量规则:对于一个volatile域的写操作,happens-before于任意后续对这个volatile域的读。 3.传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。

在akka中的Actor模型中,每个Actor实例在同一个时刻只有一个线程在调度(程序顺序规则的 happens-before);并且次Actor被调度执行message完毕后,都会修改当前Actor的一个volatile变量,代码如下: final def run = { try { if (!isClosed) { //Volatile read, needed here processAllSystemMessages() //First, deal with any system messages processMailbox() //Then deal with messages `} }finally { setAsIdle() //Volatile write, needed here dispatcher.registerForExecution(this, false, false) } }

在finally{}中setAsIdle()方法是修改一个volatile变量

@tailrec final def setAsIdle(): Boolean = { val s = status updateStatus(s, s & ~Scheduled) || setAsIdle() }

方法processMailbox() 处理当前actor收到的message

@tailrec private final def processMailbox( left: Int = java.lang.Math.max(dispatcher.throughput, 1), deadlineNs: Long = if (dispatcher.isThroughputDeadlineTimeDefined == true) System.nanoTime + dispatcher.throughputDeadlineTime.toNanos else 0L): Unit = if (shouldProcessMessage) { val next = dequeue() if (next ne null) { if (Mailbox.debug) println(actor.self + " processing message " + next) actor invoke next if (Thread.interrupted()) throw new InterruptedException("Interrupted while processing actor messages") processAllSystemMessages() if ((left > 1) && ((dispatcher.isThroughputDeadlineTimeDefined == false) || (System.nanoTime - deadlineNs) < 0)) processMailbox(left - 1, deadlineNs) } } 在每次处理邮箱中的message之前if(shouldProcessMessage)都会获取一个vloatile的状态值 final def shouldProcessMessage: Boolean = (status & shouldNotProcessMask) == 0

那么在上面的代码片段中就是使用了一个volatile变量的写、读操作 的happens-before规则来实现happens-before的传递性,如图: wechatimg2 最终Actor模型保证了: “在时刻M1,Actor A1被线程T1所执行处理消息m0,内部状态S发生改变,假设S=1; 在时刻M2, Actor A1被线程T2所执行去处理消息m1, 此刻Actor A1必然能观察到S==1,而不会出现S的值在内存中不可见的问题”