#onenote# akka 2

Dispatchers

Dispatchers

An Akka MessageDispatcher is what makes Akka Actors “tick”, it is the engine of the machine so to speak.

All MessageDispatcher implementations are also an ExecutionContext, which means that they can be

used to execute arbitrary code, for instance Futures.

Akka MessageDispatcher 是维持 Akka Actor “运作”的部分, 可以说它是整个机器的引擎. 所有的MessageDispatcher 实现也同时是一个 ExecutionContext, 这意味着它们可以用来执行任何代码, 

缺省派发器

在没有为 Actor作配置的情况下,每个 ActorSystem 将有一个缺省的派发器。 缺省派发器是可配置的,缺省情况下是一个确定的default-executor Dispatcher。如果通过传递ExecutionContext 来创建ActorSystem ,在ActorSystem中,此ExecutionContext 将作为所有派发器的defalut-executor 。如果没有指定ExecutionContext,将后退到akka.actor.default-dispatcher.default-executor.fallback executor。缺省情况下的”fork-join-executor”,在大多数情况下拥有非常好的性能。

AkkaJava内存模型的关系

不管你使用的Typesafe系统是Scala版本还是Java版本,都可以使你编写并发程序的过程变得更加容易。这篇文章主要讨论的是Typesafe系统,特别是针对Akka在并发程序中对共享内存的处理部分。

Java内存模型

在之前的Java 5 版本中,Java内存模型的定义是很值得商榷的。以至于在共享内存环境下的多线程处理的结果变得多种多样,比如:

      1. 线程读取不到其他线程写入的值:内存可见性问题
      2. 线程得到了其他线程的“非正常”行为,这也是因为底层指令没有按照期望的顺序执行的结果:指令重排序问题

Java 5版本的JSR 133规范其实已经解决了很多这样的问题。首先Java内存模型是以先序执行原则为前提的规则集合,也就是说它限制的结果是内存的访问必须是依次进行,可是它同时又允许上述的行为乱序的执行。下面是一些规则的例子:

      1. 监控锁规则:在同一把锁的获取之前必须已经进行了锁的释放
      2. Volatile变量规则:对同一个volatile变量的读取必须在对其写入之后

尽管Java内存模型表面上看很复杂,但是在规范的制定上一直在寻求高可用性以及使其具有可编写高性能、扩展性良好的并发程序结构。

角色(Actor)和Java内存模型

针对Akka中的角色(Actor)实现,多线程可以有两种方式来对共享内存进行操作:

      1. 如果消息被发送给一个角色(Actor)。在大多数情况下消息是不可变的,但是也有可能消息并不是如理想中的那样完全不可变化,如果没有先序执行规则的保证,接受消息的角色(Actor)有可能只会看到初始化不完全的数据或者更严重的根本看不到。
      2. 如果角色(Actor)通过消息处理改变了内部状态,然后处理其他的消息时又获取内部状态。在这种情况下你需要注意的是角色(Actor)模型并不能保证同一线程可以对不同的消息用相同的角色(Actor)处理。

为了避免角色(Actor)之间的可见性和重排序问题,Akka提供了下面两个先序执行的原则来保证:

      1. 角色(Actor)发送规则:发送消息给一个角色(Actor)的操作必须在同一个角色(Actor)接受了那条消息之前发生。
      2. 角色(Actor)后续处理规则:同一角色(Actor)的消息处理必须是串行的。

注意:通常意义下也就是当下一消息被角色(Actor)处理的时候,角色(Actor)内部字段的变化在当前是可见的。因此角色(Actor)中的字段不需要被声明为volatile,也不需要是等效的。

上述两个原则只对同一角色(Actor)实例有效,如果使用的是不同的角色(Actor)则没有任何作用。

FutureJava内存模型

注册在Future上的所有回调必须在Future操作完成之后执行。

建议多使用final变量,如果使用了过多的非final变量也必须同时被标识为volatile以便可以在回调中使用字段的最新值。

如果使用过多引用类型,这种情况下必须保证引用指向的实例是线程安全的。我们强烈建议不要使用对象锁,因为它可能造成性能低下,并且最严重的是可能导致死锁的产生。这其实也是使用synchronized的危险所在。

软件事务内存(STM)Java内存模型

Akka的软件事务内存也支持先序执行规则:

事务引用规则:针对同一事务引用的成功写的提交操作必须发生在同一事务引用的后续读操作之前。

这个规则看起来和Java内存模型中的volatile变量很相似。当前版本的Akka软件事务模型支持延迟写入,因此对于共享内存的实际的写操作只有在事务提交的时候才会执行。事务中的所有写操作都会被置于本地缓冲并对其他事务不可见的,这就保证了不会发生脏读现象。

Akka中这些规则到底是怎样的这都是实现细节而且都是一直在变动的,具体的下班取决于使用的配置。但是不管怎样他们都是构建在比如监控锁规则或者volatile变量规则这些Java虚拟机模型规则之上的。这就是说,如果你使用Akka,是不用添加同步来保证先序执行的关系的,因为这些Akka已经为你做了。你只需要专注于业务逻辑即可,Akka框架会替你做好这些规则的保证。

角色(Actor)和共享可变状态

但是毕竟Akka是运行在Java虚拟机上的,当然还是要遵守一些规则的。

使用内部角色(Actor)状态并且将它暴露给其他线程

01

class MyActor extends Actor{

02

    var state=

03

    def receive ={

04

        case _=>

05

           //错误

06

           //相当的糟糕,共享可变状态

07

           //会使你的应用出现奇怪的行为

08

           Future { state = NewState }

09

           anotherActor ? message onSuccess {r => state = r }

10

11

           //相当糟糕,“sender”会因为每条消息而改变

12

           //共享可变状态BUG

13

           Future {expensiveCalculation(sender())}

14

15

           //正确

16

           //完全安全,“self”可以封装

17

           Future {expensiveCalculation() } onComplete { f=> self ! f.value.get }

18

19

           //完全安全,我们封装一个固定值

20

           //而且它是一个ActorRef,这个对象是线程安全的

21

           val currentSender = sender()

22

           Future {expensiveCalculation(currentSender)}

23

    }

24

}

Pasted from <http://ifeve.com/akka-doc-java-jmm/>

Machine generated alternative text:
3.4.4 Types of dispatchers
There are 4 difTerent types of message dispatchers:
Dispatcher
? This is an event-based dispatcher thai binds a set ofActoms to a thiead pooL It is the default dispatcher
used ilorie is not specified
? Sharability: Iinliniited
? Mailboxes: Any. creates one per Actor
? Use cases: l)1ault dispatcher. Buikheading
? Drtsen by: java. uti].. concurrent. Executorservice speci[y using 揺x
ecutor? using 揻ork-join-executor. 搕hread.pool.executor? or the FQCN of an
akka .dispatcher. ExecutorServiceConfigurator
PinnedDispatcher
? This dispatcher dedicates a unique thread for each actor using it; i.e. each actor will have iLs Mn
thread poo1 with only one thread in the pooL
? Sharability: Noe
? Mailboxes: Any. creates one perActor
? Use cases: Butkheading
? DrIven by: Any aicka. dispatch. ThreadPoolExecutorConfigurator [ default a
搕hread-pool-executor?

Machine generated alternative text:
? This is an executor based event driven dispatcher that will try lo redistribute work from busy actors to
idle actors.
? All the actors share a single Mailbox that they get their messages from.
? It is assumed that all actors using the same instance of this dispatcher can process all messages that
have been sent to one of the actors: ie the actors belong to a pool of actors, and to the client there is
no guarantee about which actor instance actually processes a given message.
? Sharahility: Actors of the same type only
? Mailboxes: Any. creates one for all Actors
? Use cases: Work-sharing
? DrIven by: java. util. concurrent. axecutorservice specit using 揺x
ecutor? using 戫ork-join.executor? 搕hread-pool.executor? or the FQCN of an
akka . dispatcher .Exe cutorSe rviceConfigurator
? Note that you can not use a BalancingDiapatcher as a Router l)lspatcher. tYou can however
use it for the Routesi
CaflingThreadl)ispalcher
? This dispatcher nins invocations on t韙 cunent thread only. This dispatcher does not create any trw
threads, but it can be used from different threads concurrently for the same actor. See CallingThrcad
Dispas cher for details and restrictions.
? Sharahility: Unlimited
? Mailboxes: Any. creates one per Actor per Thread ton demand
? Use cases: 慣esting
? Driven by? The cathng thread (duh)

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s