1.Actor模型

在使用Java進(jìn)行并發(fā)編程時(shí)需要特別的關(guān)注鎖和內(nèi)存原子性等一系列線程問(wèn)題,而Actor模型內(nèi)部的狀態(tài)由它自己維護(hù)即它內(nèi)部數(shù)據(jù)只能由它自己修改(通過(guò)消息傳遞來(lái)進(jìn)行狀態(tài)修改),所以使用Actors模型進(jìn)行并發(fā)編程可以很好地避免這些問(wèn)題,Actor由狀態(tài)(state)、行為(Behavior)和郵箱(mailBox)三部分組成

  1. 狀態(tài)(state):Actor中的狀態(tài)指的是Actor對(duì)象的變量信息,狀態(tài)由Actor自己管理,避免了并發(fā)環(huán)境下的鎖和內(nèi)存原子性等問(wèn)題

  2. 行為(Behavior):行為指定的是Actor中計(jì)算邏輯,通過(guò)Actor接收到消息來(lái)改變Actor的狀態(tài)

  3. 郵箱(mailBox):郵箱是Actor和Actor之間的通信橋梁,郵箱內(nèi)部通過(guò)FIFO消息隊(duì)列來(lái)存儲(chǔ)發(fā)送方Actor消息,接受方Actor從郵箱隊(duì)列中獲取消息

Actor的基礎(chǔ)就是消息傳遞

2.使用Actor模型的好處:

  1. 事件模型驅(qū)動(dòng)--Actor之間的通信是異步的,即使Actor在發(fā)送消息后也無(wú)需阻塞或者等待就能夠處理其他事情

  2. 強(qiáng)隔離性--Actor中的方法不能由外部直接調(diào)用,所有的一切都通過(guò)消息傳遞進(jìn)行的,從而避免了Actor之間的數(shù)據(jù)共享,想要
    觀察到另一個(gè)Actor的狀態(tài)變化只能通過(guò)消息傳遞進(jìn)行詢問(wèn)

  3. 位置透明--無(wú)論Actor地址是在本地還是在遠(yuǎn)程機(jī)上對(duì)于代碼來(lái)說(shuō)都是一樣的

  4. 輕量性--Actor是非常輕量的計(jì)算單機(jī),單個(gè)Actor僅占400多字節(jié),只需少量?jī)?nèi)存就能達(dá)到高并發(fā)

3.Actor模型原理

以下通過(guò)學(xué)生與教師之間的郵件通信來(lái)理解akka中的Actor模型

學(xué)生-教師的消息傳遞

首先先只考慮學(xué)生單向發(fā)送消息給教師(學(xué)生--->教師),如下圖:
iOS培訓(xùn),Swift培訓(xùn),蘋果開(kāi)發(fā)培訓(xùn),移動(dòng)開(kāi)發(fā)培訓(xùn)

圖解:

  1. 學(xué)生創(chuàng)建一個(gè)ActorSystem

  2. 通過(guò)ActorSystem創(chuàng)建ActorRef,將QuoteRequest消息發(fā)送到ActorRef(教師代理)

  3. ActorRef(教師代理)消息傳遞到Dispatcher中

  4. Dispatcher依次的將消息發(fā)送到TeacherActor的郵箱中

  5. Dispatcher將郵箱推送到一條線程中

  6. 郵箱取出一條消息并委派給TeacherActor的receive方法

下面再詳細(xì)的解釋每一步驟

StudentSimulatorApp主程序詳解:

首先StudentSimulatorApp會(huì)先啟動(dòng)JVM并初始化ActorSystem
iOS培訓(xùn),Swift培訓(xùn),蘋果開(kāi)發(fā)培訓(xùn),移動(dòng)開(kāi)發(fā)培訓(xùn)

如上圖所示,StudentSimulatorApp的主要工作為:

  1. 創(chuàng)建ActorSystem

    • ActorSystem作為頂級(jí)Actor,可以創(chuàng)建和停止Actors,甚至可關(guān)閉整個(gè)Actor環(huán)境,
      此外Actors是按層次劃分的,ActorSystem就好比Java中的Object對(duì)象,Scala中的Any,
      是所有Actors的根,當(dāng)你通過(guò)ActorSystem的actof方法創(chuàng)建Actor時(shí),實(shí)際就是在ActorSystem
      下創(chuàng)建了一個(gè)子Actor。
      可通過(guò)以下代碼來(lái)初始化ActorSystem

      val system = ActorSystem("UniversityMessageSystem")

  2. 通過(guò)ActorSystem創(chuàng)建TeacherActor的代理(ActorRef)ActorSystem通過(guò)actorOf創(chuàng)建Actor,但其并不返回TeacherActor而是返
    回一個(gè)類型為ActorRef的東西。
    ActorRef作為Actor的代理,使得客戶端并不直接與Actor對(duì)話,這種Actor
    模型也是為了避免TeacherActor的自定義/私有方法或變量被直接訪問(wèn),所
    以你最好將消息發(fā)送給ActorRef,由它去傳遞給目標(biāo)Actor

    • 看看TeacherActor的代理的創(chuàng)建代碼

      val teacherActorRef:ActorRef = system.actorOf(Props[TeacherActor])

  3. 發(fā)送QuoteRequest消息到代理中

    • 你只需通過(guò)!方法將QuoteReques消息發(fā)送給ActorRef(注意:ActorRef也有個(gè)tell方法,其作用就委托回調(diào)給!)

      techerActorRef!QuoteRequest
      等價(jià)于teacherActorRef.tell(QuoteRequest, teacherActorRef)

完整StudentSimulatorApp代碼

object StudentSimulatorApp extends App{
?//初始化ActorSystem
?val actorSystem=ActorSystem("UniversityMessageSystem")
?//構(gòu)建teacherActorRef
?val teacherActorRef=actorSystem.actorOf(Props[TeacherActor])
?//發(fā)送消息給TeacherActor
?teacherActorRef! QuoteRequest
?Thread.sleep (2000)
?//關(guān)閉 ActorSystem,如果不關(guān)閉JVM將不會(huì)退出
?actorSystem.shutdown()
}

QuoteRequest類

object TeacherProtocol{
?case class QuoteRequest() //請(qǐng)求
?case class QuoteResponse(quoteString:String) //響應(yīng)
}

Dispatcher和MailBox

ActorRef將消息處理能力委派給Dispatcher,實(shí)際上,當(dāng)我們創(chuàng)建ActorSystem和ActorRef時(shí),
Dispatcher和MailBox就已經(jīng)被創(chuàng)建了

iOS培訓(xùn),Swift培訓(xùn),蘋果開(kāi)發(fā)培訓(xùn),移動(dòng)開(kāi)發(fā)培訓(xùn)

  • MailBox

    • 每個(gè)Actor都有一個(gè)MailBox,同樣,Teacher也有個(gè)MailBox,其會(huì)檢查MailBox并處理消息。
      MailBox內(nèi)部采用的是FIFO隊(duì)列來(lái)存儲(chǔ)消息,有一點(diǎn)不同的是,現(xiàn)實(shí)中我們的最新郵件
      會(huì)在郵箱的最前面。

  • Dispatcher

    • 看看MailBox的實(shí)現(xiàn),沒(méi)錯(cuò),其實(shí)現(xiàn)了Runnable接口

      private[akka] abstract class Mailbox(val messageQueue: MessageQueue) extends SystemMessageQueue with Runnable

    • Dispatcher從ActorRef中獲取消息并傳遞給MailBox,Dispatcher封裝了一個(gè)線程池,之后在
      線程池中執(zhí)行MailBox。

      protected[akka] override def registerForExecution(mbox: Mailbox, ...): Boolean = {
      ? ...
      ?try {
      ?executorService execute mbox
      ?...
      }

    • 為什么能執(zhí)行MailBox?

TeacherActor

iOS培訓(xùn),Swift培訓(xùn),蘋果開(kāi)發(fā)培訓(xùn),移動(dòng)開(kāi)發(fā)培訓(xùn)

  • 當(dāng)ActorRef發(fā)送消息調(diào)用目標(biāo)Actor的reveive方法時(shí),MailBox中的run方法被執(zhí)行,接著從消息隊(duì)列中取出一條消息并傳遞給Actor處理

    class TeacherActor extends Actor {
    ?val quotes = List(
    ??"Moderation is for cowards",
    ??"Anything worth doing is worth overdoing",
    ??"The trouble is you think you have time",
    ??"You never gonna know if you never even try")
    ?def receive = {
    ??case QuoteRequest => {
    ??import util.Random
    ??//從list中隨機(jī)選出一條消息作為回應(yīng)(這里只print并沒(méi)回應(yīng)學(xué)生的請(qǐng)求)
    ??val quoteResponse=QuoteResponse(quotes(Random.nextInt(quotes.size)))
    ??println (quoteResponse)
    ??}
    ?}
    }
    TeacherActor的receive方法將匹配QuoteRequest消息

這里有個(gè)國(guó)外博主寫的Akka系列博客都很贊,分享給大家!

本文參考資料

http://www.cnblogs.com/MOBIN/p/7236893.html