精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從Java走進Scala:一步步教你使用Scala Actor

開發 后端
“actor” 實現在稱為 actor 的執行實體之間使用消息傳遞進行協作,而Scala Actor是Scala并發編程中最重要的一個機制。本文生趣的介紹了如何使用Scala Actor。

前一篇文章 中,我討論了構建并發代碼的重要性(無論是否是 Scala 代碼),還討論了在編寫并發代碼時開發人員面對的一些問題,包括不要鎖住太多東西、不要鎖住太少東西、避免死鎖、避免生成太多線程等等。

51CTO編輯推薦:Scala編程語言專題

這些理論問題太沉悶了。為了避免讀者覺得失望,我與您一起研究了 Scala 的一些并發構造,首先是在 Scala 中直接使用 Java 語言的并發庫的基本方法,然后討論 Scala API 中的 MailBox 類型。盡管這兩種方法都是可行的,但是它們并不是 Scala 實現并發性的主要機制。

真正提供并發性的是 Scala 的 actor。

什么是 “actor”?

“actor” 實現在稱為 actor 的執行實體之間使用消息傳遞進行協作(注意,這里有意避免使用 “進程”、“線程” 或 “機器” 等詞匯)。盡管它聽起來與 RPC 機制有點兒相似,但是它們是有區別的。RPC 調用(比如 Java RMI 調用)會在調用者端阻塞,直到服務器端完成處理并發送回某種響應(返回值或異常),而消息傳遞方法不會阻塞調用者,因此可以巧妙地避免死鎖。

僅僅傳遞消息并不能避免錯誤的并發代碼的所有問題。另外,這種方法還有助于使用 “不共享任何東西” 編程風格,也就是說不同的 actor 并不訪問共享的數據結構(這有助于促進封裝 actor,無論 actor 是 JVM 本地的,還是位于其他地方) — 這樣就完全不需要同步了。畢竟,如果不共享任何東西,并發執行就不涉及任何需要同步的東西。

這不算是對 actor 模型的正規描述,而且毫無疑問,具有更正規的計算機科學背景的人會找到各種更嚴謹的描述方法,能夠描述 actor 的所有細節。但是對于本文來說,這個描述已經夠了。在網上可以找到更詳細更正規的描述,還有一些學術文章詳細討論了 actor 背后的概念(請您自己決定是否要深入學習這些概念)。現在,我們來看看 Scala actors API。

#p#

Scala actor

使用 actor 根本不困難,只需使用 Actor 類的 actor 方法創建一個 actor,見清單 1:

清單 1. 開拍!

  1. import scala.actors._, Actor._  
  2.  
  3. package com.tedneward.scalaexamples.scala.V4  
  4. {  
  5.   object Actor1  
  6.   {  
  7.     def main(args : Array[String]) =  
  8.     {  
  9.       val badActor =  
  10.         actor  
  11.         {  
  12.           receive  
  13.           {  
  14.             case msg => System.out.println(msg)  
  15.           }  
  16.         }  
  17.         
  18.       badActor ! "Do ya feel lucky, punk?" 
  19.     }  
  20.   }  
  21. }  
  22.    

這里同時做了兩件事。

首先,我們從 Scala Actors 庫的包中導入了這個庫,然后從庫中直接導入了 Actor 類的成員;第二步并不是完全必要的,因為在后面的代碼中可以使用 Actor.actor 替代 actor,但是這么做能夠表明 actor 是語言的內置結構并(在一定程度上)提高代碼的可讀性。

下一步是使用 actor 方法創建 actor 本身,這個方法通過參數接收一個代碼塊。在這里,代碼塊執行一個簡單的 receive(稍后討論)。結果是一個 actor,它被存儲在一個值引用中,供以后使用。

請記住,除了消息之外,actor 不使用其他通信方法。使用 ! 的代碼行實際上是一個向 badActor 發送消息的方法,這可能不太直觀。Actor 內部還包含另一個 MailBox 元素(已討論);! 方法接收傳遞過來的參數(在這里是一個字符串),把它發送給郵箱,然后立即返回。

消息交付給 actor 之后,actor 通過調用它的 receive 方法來處理消息;這個方法從郵箱中取出第一個可用的消息,把它交付給一個模式匹配塊。注意,因為這里沒有指定模式匹配的類型,所以任何消息都是匹配的,而且消息被綁定到 msg 名稱(為了打印它)。

一定要注意一點:對于可以發送的類型,沒有任何限制 — 不一定要像前面的示例那樣發送字符串。實際上,基于 actor 的設計常常使用 Scala case 類攜帶實際消息本身,這樣就可以根據 case 類的參數/成員的類型提供隱式的 “命令” 或 “動作”,或者向動作提供數據。

例如,假設希望 actor 用兩個不同的動作來響應發送的消息;新的實現可能與清單 2 相似:

清單 2. 嗨,我是導演!

  1. object Actor2  
  2. {  
  3.   case class Speak(line : String);  
  4.   case class Gesture(bodyPart : String, action : String);  
  5.   case class NegotiateNewContract;  
  6.  
  7.   def main(args : Array[String]) =  
  8.   {  
  9.     val badActor =  
  10.       actor  
  11.       {  
  12.         receive  
  13.         {  
  14.           case NegotiateNewContract =>  
  15.             System.out.println("I won't do it for less than $1 million!")  
  16.           case Speak(line) =>  
  17.             System.out.println(line)  
  18.           case Gesture(bodyPart, action) =>  
  19.             System.out.println("(" + action + "s " + bodyPart + ")")  
  20.           case _ =>  
  21.             System.out.println("Huh? I'll be in my trailer.")  
  22.         }  
  23.       }  
  24.       
  25.     badActor ! NegotiateNewContract  
  26.     badActor ! Speak("Do ya feel lucky, punk?")  
  27.     badActor ! Gesture("face""grimaces")  
  28.     badActor ! Speak("Well, do ya?")  
  29.   }  
  30. }  

到目前為止,看起來似乎沒問題,但是在運行時,只協商了新合同;在此之后,JVM 終止了。初看上去,似乎是生成的線程無法足夠快地響應消息,但是要記住在 actor 模型中并不處理線程,只處理消息傳遞。這里的問題其實非常簡單:一次接收使用一個消息,所以無論隊列中有多少個消息正在等待處理都無所謂,因為只有一次接收,所以只交付一個消息。

糾正這個問題需要對代碼做以下修改,見清單 3:

◆把 receive 塊放在一個接近無限的循環中。

◆創建一個新的 case 類來表示什么時候處理全部完成了。

清單 3. 現在我是一個更好的導演!

  1. object Actor2  
  2. {  
  3.   case class Speak(line : String);  
  4.   case class Gesture(bodyPart : String, action : String);  
  5.   case class NegotiateNewContract;  
  6.   case class ThatsAWrap;  
  7.  
  8.   def main(args : Array[String]) =  
  9.   {  
  10.     val badActor =  
  11.       actor  
  12.       {  
  13.         var done = false 
  14.         while (! done)  
  15.         {  
  16.           receive  
  17.           {  
  18.             case NegotiateNewContract =>  
  19.               System.out.println("I won't do it for less than $1 million!")  
  20.             case Speak(line) =>  
  21.               System.out.println(line)  
  22.             case Gesture(bodyPart, action) =>  
  23.               System.out.println("(" + action + "s " + bodyPart + ")")  
  24.             case ThatsAWrap =>  
  25.               System.out.println("Great cast party, everybody! See ya!")  
  26.               done = true 
  27.             case _ =>  
  28.               System.out.println("Huh? I'll be in my trailer.")  
  29.           }  
  30.         }  
  31.       }  
  32.       
  33.     badActor ! NegotiateNewContract  
  34.     badActor ! Speak("Do ya feel lucky, punk?")  
  35.     badActor ! Gesture("face""grimaces")  
  36.     badActor ! Speak("Well, do ya?")  
  37.     badActor ! ThatsAWrap  
  38.   }  
  39. }  

這下行了!使用 Scala actor 就這么容易。

#p#

并發地執行動作

上面的代碼沒有反映出并發性 — 到目前為止給出的代碼更像是另一種異步的方法調用形式,您看不出區別。(從技術上說,在第二個示例中引入接近無限循環之前的代碼中,可以猜出有一定的并發性存在,但這只是偶然的證據,不是明確的證明)。

為了證明在幕后確實有多個線程存在,我們深入研究一下前一個示例:

清單 4. 我要拍特寫了

  1. object Actor3  
  2. {  
  3.   case class Speak(line : String);  
  4.   case class Gesture(bodyPart : String, action : String);  
  5.   case class NegotiateNewContract;  
  6.   case class ThatsAWrap;  
  7.  
  8.   def main(args : Array[String]) =  
  9.   {  
  10.     def ct =  
  11.       "Thread " + Thread.currentThread().getName() + ": " 
  12.     val badActor =  
  13.       actor  
  14.       {  
  15.         var done = false 
  16.         while (! done)  
  17.         {  
  18.           receive  
  19.           {  
  20.             case NegotiateNewContract =>  
  21.               System.out.println(ct + "I won't do it for less than $1 million!")  
  22.             case Speak(line) =>  
  23.               System.out.println(ct + line)  
  24.             case Gesture(bodyPart, action) =>  
  25.               System.out.println(ct + "(" + action + "s " + bodyPart + ")")  
  26.             case ThatsAWrap =>  
  27.               System.out.println(ct + "Great cast party, everybody! See ya!")  
  28.               done = true 
  29.             case _ =>  
  30.               System.out.println(ct + "Huh? I'll be in my trailer.")  
  31.           }  
  32.         }  
  33.       }  
  34.       
  35.     System.out.println(ct + "Negotiating...")  
  36.     badActor ! NegotiateNewContract  
  37.     System.out.println(ct + "Speaking...")  
  38.     badActor ! Speak("Do ya feel lucky, punk?")  
  39.     System.out.println(ct + "Gesturing...")  
  40.     badActor ! Gesture("face""grimaces")  
  41.     System.out.println(ct + "Speaking again...")  
  42.     badActor ! Speak("Well, do ya?")  
  43.     System.out.println(ct + "Wrapping up")  
  44.     badActor ! ThatsAWrap  
  45.   }  
  46. }  

運行這個新示例,就會非常明確地發現確實有兩個不同的線程:

◆main 線程(所有 Java 程序都以它開始)

◆Thread-2 線程,它是 Scala Actors 庫在幕后生成的

因此,在啟動第一個 actor 時,本質上已經開始了多線程執行。

但是,習慣這種新的執行模型可能有點兒困難,因為這是一種全新的并發性考慮方式。例如,請考慮 前一篇文章 中的 Producer/Consumer 模型。那里有大量代碼,尤其是在 Drop 類中,我們可以清楚地看到線程之間,以及線程與保證所有東西同步的監視器之間有哪些交互活動。為了便于參考,我在這里給出前一篇文章中的 V3 代碼:

清單 5. ProdConSample,v3 (Scala)

  1. package com.tedneward.scalaexamples.scala.V3  
  2. {  
  3.   import concurrent.MailBox  
  4.   import concurrent.ops._  
  5.  
  6.   object ProdConSample  
  7.   {  
  8.     class Drop  
  9.     {  
  10.       private val m = new MailBox()  
  11.         
  12.       private case class Empty()  
  13.       private case class Full(x : String)  
  14.         
  15.       m send Empty()  // initialization  
  16.         
  17.       def put(msg : String) : Unit =  
  18.       {  
  19.         m receive  
  20.         {  
  21.           case Empty() =>  
  22.             m send Full(msg)  
  23.         }  
  24.       }  
  25.         
  26.       def take() : String =  
  27.       {  
  28.         m receive  
  29.         {  
  30.           case Full(msg) =>  
  31.             m send Empty(); msg  
  32.         }  
  33.       }  
  34.     }  
  35.     
  36.     def main(args : Array[String]) : Unit =  
  37.     {  
  38.       // Create Drop  
  39.       val drop = new Drop()  
  40.         
  41.       // Spawn Producer  
  42.       spawn  
  43.       {  
  44.         val importantInfo : Array[String] = Array(  
  45.           "Mares eat oats",  
  46.           "Does eat oats",  
  47.           "Little lambs eat ivy",  
  48.           "A kid will eat ivy too" 
  49.         );  
  50.           
  51.         importantInfo.foreach((msg) => drop.put(msg))  
  52.         drop.put("DONE")  
  53.       }  
  54.         
  55.       // Spawn Consumer  
  56.       spawn  
  57.       {  
  58.         var message = drop.take()  
  59.         while (message != "DONE")  
  60.         {  
  61.           System.out.format("MESSAGE RECEIVED: %s%n", message)  
  62.           message = drop.take()  
  63.         }  
  64.       }  
  65.     }  
  66.   }  
  67. }  
  68.    

盡管看到 Scala 如何簡化這些代碼很有意思,但是它實際上與原來的 Java 版本沒有概念性差異。現在,看看如果把 Producer/Consumer 示例的基于 actor 的版本縮減到最基本的形式,它會是什么樣子:

清單 6. Take 1,開拍!生產!消費!

  1. object ProdConSample1  
  2. {  
  3.   case class Message(msg : String)  
  4.     
  5.   def main(args : Array[String]) : Unit =  
  6.   {  
  7.     val consumer =  
  8.       actor  
  9.       {  
  10.         var done = false 
  11.         while (! done)  
  12.         {  
  13.           receive  
  14.           {  
  15.             case msg =>  
  16.               System.out.println("Received message! -> " + msg)  
  17.               done = (msg == "DONE")  
  18.           }  
  19.         }  
  20.       }  
  21.       
  22.     consumer ! "Mares eat oats" 
  23.     consumer ! "Does eat oats" 
  24.     consumer ! "Little lambs eat ivy" 
  25.     consumer ! "Kids eat ivy too" 
  26.     consumer ! "DONE"        
  27.   }  
  28. }  

第一個版本確實簡短多了,而且在某些情況下可能能夠完成所需的所有工作;但是,如果運行這段代碼并與以前的版本做比較,就會發現一個重要的差異 — 基于 actor 的版本是一個多位置緩沖區,而不是我們以前使用的單位置緩沖。這看起來是一項改進,而不是缺陷,但是我們要通過對比確認這一點。我們來創建 Drop 的基于 actor 的版本,在這個版本中所有對 put() 的調用必須由對 take() 的調用進行平衡。

幸運的是,Scala Actors 庫很容易模擬這種功能。希望讓 Producer 一直阻塞,直到 Consumer 接收了消息;實現的方法很簡單:讓 Producer 一直阻塞,直到它從 Consumer 收到已經接收消息的確認。從某種意義上說,這就是以前的基于監視器的代碼所做的,那個版本通過對鎖對象使用監視器發送這種信號。

#p#

在 Scala Actors 庫中,最容易的實現方法是使用 !? 方法而不是 ! 方法(這樣就會一直阻塞到收到確認時)。(在 Scala Actors 實現中,每個 Java 線程都是一個 actor,所以回復會發送到與 main 線程隱式關聯的郵箱)。這意味著 Consumer 需要發送某種確認;這要使用隱式繼承的 reply(它還繼承 receive 方法),見清單 7:

清單 7. Take 2,開拍!

  1. object ProdConSample2  
  2. {  
  3.   case class Message(msg : String)  
  4.     
  5.   def main(args : Array[String]) : Unit =  
  6.   {  
  7.     val consumer =  
  8.       actor  
  9.       {  
  10.         var done = false 
  11.         while (! done)  
  12.         {  
  13.           receive  
  14.           {  
  15.             case msg =>  
  16.               System.out.println("Received message! -> " + msg)  
  17.               done = (msg == "DONE")  
  18.               reply("RECEIVED")  
  19.           }  
  20.         }  
  21.       }  
  22.       
  23.     System.out.println("Sending....")  
  24.     consumer !? "Mares eat oats" 
  25.     System.out.println("Sending....")  
  26.     consumer !? "Does eat oats" 
  27.     System.out.println("Sending....")  
  28.     consumer !? "Little lambs eat ivy" 
  29.     System.out.println("Sending....")  
  30.     consumer !? "Kids eat ivy too" 
  31.     System.out.println("Sending....")  
  32.     consumer !? "DONE"        
  33.   }  
  34. }  

如果喜歡使用 spawn 把 Producer 放在 main() 之外的另一個線程中(這非常接近最初的代碼),那么代碼可能像清單 8 這樣:

清單 8. Take 4,開拍!

  1. object ProdConSampleUsingSpawn  
  2. {  
  3.   import concurrent.ops._  
  4.  
  5.   def main(args : Array[String]) : Unit =  
  6.   {  
  7.     // Spawn Consumer  
  8.     val consumer =  
  9.       actor  
  10.       {  
  11.         var done = false 
  12.         while (! done)  
  13.         {  
  14.           receive  
  15.           {  
  16.             case msg =>  
  17.               System.out.println("MESSAGE RECEIVED: " + msg)  
  18.               done = (msg == "DONE")  
  19.               reply("RECEIVED")  
  20.           }  
  21.         }  
  22.       }  
  23.     
  24.     // Spawn Producer  
  25.     spawn  
  26.     {  
  27.       val importantInfo : Array[String] = Array(  
  28.         "Mares eat oats",  
  29.         "Does eat oats",  
  30.         "Little lambs eat ivy",  
  31.         "A kid will eat ivy too",  
  32.         "DONE" 
  33.       );  
  34.         
  35.       importantInfo.foreach((msg) => consumer !? msg)  
  36.     }  
  37.   }  
  38. }  

無論從哪個角度來看,基于 actor 的版本都比原來的版本簡單多了。讀者只要讓 actor 和隱含的郵箱自己發揮作用即可。

但是,這并不簡單。actor 模型完全顛覆了考慮并發性和線程安全的整個過程;在以前的模型中,我們主要關注共享的數據結構(數據并發性),而現在主要關注操作數據的代碼本身的結構(任務并發性),盡可能少共享數據。請注意 Producer/Consumer 示例的不同版本的差異。在以前的示例中,并發功能是圍繞 Drop 類(有界限的緩沖區)顯式編寫的。在本文中的版本中,Drop 甚至沒有出現,重點在于兩個 actor(線程)以及它們之間的交互(通過不共享任何東西的消息)。

當然,仍然可以用 actor 構建以數據為中心的并發構造;只是必須采用稍有差異的方式。請考慮一個簡單的 “計數器” 對象,它使用 actor 消息傳達 “increment” 和 “get” 操作,見清單 9:

清單 9. Take 5,計數!

  1. object CountingSample  
  2.  {  
  3.    case class Incr  
  4.    case class Value(sender : Actor)  
  5.    case class Lock(sender : Actor)  
  6.    case class UnLock(value : Int)  
  7.    
  8.    class Counter extends Actor  
  9.    {  
  10.      override def act(): Unit = loop(0)  
  11.  
  12.      def loop(value: int): Unit = {  
  13.        receive {  
  14.          case Incr()   => loop(value + 1)  
  15.          case Value(a) => a ! value; loop(value)  
  16.          case Lock(a)  => a ! value  
  17.                           receive { case UnLock(v) => loop(v) }  
  18.          case _        => loop(value)  
  19.        }  
  20.      }  
  21.    }  
  22.      
  23.    def main(args : Array[String]) : Unit =  
  24.    {  
  25.      val counter = new Counter  
  26.      counter.start()  
  27.      counter ! Incr()  
  28.      counter ! Incr()  
  29.      counter ! Incr()  
  30.      counter ! Value(self)  
  31.      receive { case cvalue => Console.println(cvalue) }      
  32.      counter ! Incr()  
  33.      counter ! Incr()  
  34.      counter ! Value(self)  
  35.      receive { case cvalue => Console.println(cvalue) }      
  36.    }  
  37.  }  

#p#

為了進一步擴展 Producer/Consumer 示例,清單 10 給出一個在內部使用 actor 的 Drop 版本(這樣,其他 Java 類就可以使用這個 Drop,而不需要直接調用 actor 的方法):

清單 10. 在內部使用 actor 的 Drop

  1. object ActorDropSample  
  2. {  
  3.   class Drop  
  4.   {  
  5.     private case class Put(x: String)  
  6.     private case object Take  
  7.     private case object Stop  
  8.  
  9.     private val buffer =  
  10.       actor  
  11.       {  
  12.         var data = "" 
  13.         loop  
  14.         {  
  15.           react  
  16.           {  
  17.             case Put(x) if data == "" =>  
  18.               data = x; reply()  
  19.             case Take if data != "" =>  
  20.               val r = data; data = ""; reply(r)  
  21.             case Stop =>  
  22.               reply(); exit("stopped")  
  23.           }  
  24.         }  
  25.       }  
  26.  
  27.     def put(x: String) { buffer !? Put(x) }  
  28.     def take() : String = (buffer !? Take).asInstanceOf[String]  
  29.     def stop() { buffer !? Stop }  
  30.   }  
  31.     
  32.   def main(args : Array[String]) : Unit =  
  33.   {  
  34.     import concurrent.ops._  
  35.     
  36.     // Create Drop  
  37.     val drop = new Drop()  
  38.       
  39.     // Spawn Producer  
  40.     spawn  
  41.     {  
  42.       val importantInfo : Array[String] = Array(  
  43.         "Mares eat oats",  
  44.         "Does eat oats",  
  45.         "Little lambs eat ivy",  
  46.         "A kid will eat ivy too" 
  47.       );  
  48.         
  49.       importantInfo.foreach((msg) => { drop.put(msg) })  
  50.       drop.put("DONE")  
  51.     }  
  52.       
  53.     // Spawn Consumer  
  54.     spawn  
  55.     {  
  56.       var message = drop.take()  
  57.       while (message != "DONE")  
  58.       {  
  59.         System.out.format("MESSAGE RECEIVED: %s%n", message)  
  60.         message = drop.take()  
  61.       }  
  62.       drop.stop()  
  63.     }  
  64.   }  
  65. }  

可以看到,這需要更多代碼(和更多的線程,因為每個 actor 都在一個線程池內部起作用),但是這個版本的 API 與以前的版本相同,它把所有與并發性相關的代碼都放在 Drop 內部,這正是 Java 開發人員所期望的。

actor 還有更多特性。

在規模很大的系統中,讓每個 actor 都由一個 Java 線程支持是非常浪費資源的,尤其是在 actor 的等待時間比處理時間長的情況下。在這些情況下,基于事件的 actor 可能更合適;這種 actor 實際上放在一個閉包中,閉包捕捉 actor 的其他動作。也就是說,現在并不通過線程狀態和寄存器表示代碼塊(函數)。當一個消息到達 actor 時(這時顯然需要活動的線程),觸發閉包,閉包在它的活動期間借用一個活動的線程,然后通過回調本身終止或進入 “等待” 狀態,這樣就會釋放線程。(請參見 參考資料 中 Haller/Odersky 的文章)。

在 Scala Actors 庫中,這要使用 react 方法而不是前面使用的 receive。使用 react 的關鍵是在形式上 react 不能返回,所以 react 中的實現必須重復調用包含 react 塊的代碼塊。簡便方法是使用 loop 結構創建一個接近無限的循環。這意味著 清單 10 中的 Drop 實現實際上只通過借用調用者的線程執行操作,這會減少執行所有操作所需的線程數。(在實踐中,我還沒有見過在簡單的示例中出現這種效果,所以我想我們只能暫且相信 Scala 設計者的說法)。

在某些情況下,可能選擇通過派生基本的 Actor 類(在這種情況下,必須定義 act 方法,否則類仍然是抽象的)創建一個新類,它隱式地作為 actor 執行。盡管這是可行的,但是這種思想在 Scala 社區中不受歡迎;在一般情況下,我在這里描述的方法(使用 Actor 對象中的 actor 方法)是創建 actor 的首選方法。

結束語

因為 actor 編程需要與 “傳統” 對象編程不同的風格,所以在使用 actor 時要記住幾點。

首先,actor 的主要能力來源于消息傳遞風格,而不采用阻塞-調用風格,這是它的主要特點。(有意思的是,也有使用消息傳遞作為核心機制的面向對象語言。最知名的兩個例子是 Objective-C 和 Smalltalk,還有 ThoughtWorker 的 Ola Bini 新創建的 Ioke)。如果創建直接或間接擴展 Actor 的類,那么要確保對對象的所有調用都通過消息傳遞進行。

第二,因為可以在任何時候交付消息,而且更重要的是,在發送和接收之間可能有相當長的延遲,所以一定要確保消息攜帶正確地處理它們所需的所有狀態。這種方式會:

讓代碼更容易理解(因為消息攜帶處理所需的所有狀態)。
減少 actor 訪問某些地方的共享狀態的可能性,從而減少發生死鎖或其他并發性問題的機會。
第三,actor 應該不會阻塞,您從前面的內容應該能夠看出這一點。從本質上說,阻塞是導致死鎖的原因;代碼可能產生的阻塞越少,發生死鎖的可能性就越低。

很有意思的是,如果您熟悉 Java Message Service (JMS) API,就會發現我給出的這些建議在很大程度上也適用于 JMS — 畢竟,actor 消息傳遞風格只是在實體之間傳遞消息,JMS 消息傳遞也是在實體之間傳遞消息。它們的差異在于,JMS 消息往往比較大,在層和進程級別上操作;而 actor 消息往往比較小,在對象和線程級別上操作。如果您掌握了 JMS,actor 也不難掌握。

actor 并不是解決所有并發性問題的萬靈藥,但是它們為應用程序或庫代碼的建模提供了一種新的方式,所用的構造相當簡單明了。盡管它們的工作方式有時與您預期的不一樣,但是一些行為正是我們所熟悉的 — 畢竟,我們在最初使用對象時也有點不習慣,只要經過努力,您也會掌握并喜歡上 actor。

本文來自IBMDW中國:《面向 Java 開發人員的 Scala 指南: 深入了解 Scala 并發性》。

【相關閱讀】

  1. Scala編程語言專題
  2. 從Java走進Scala:深入了解Scala并發性
  3. 從Java走進Scala:構建計算器 結合解析器組合子和case類
  4. 從Java走進Scala:構建計算器 解析器組合子入門
  5. 從Java走進Scala:簡單的計算器 case類和模式匹配
責任編輯:yangsai 來源: IBMDW
相關推薦

2017-12-25 11:50:57

LinuxArch Linux

2017-01-19 21:08:33

iOS路由構建

2020-12-24 11:19:55

JavaMapHashMap

2018-06-11 15:30:12

2024-11-18 17:12:18

C#編程.NET

2018-12-24 10:04:06

Docker存儲驅動

2019-07-09 15:23:22

Docker存儲驅動

2019-03-05 14:09:27

Docker存儲容器

2010-08-12 10:02:16

路由器NAT

2017-01-06 15:13:25

LinuxVim源代碼

2010-08-10 11:31:36

路由器配置NAT

2009-04-15 09:29:07

2016-11-02 18:54:01

javascript

2010-03-04 16:28:17

Android核心代碼

2018-04-23 14:23:12

2015-07-27 16:06:16

VMware Thin虛擬化

2011-09-05 12:36:08

路由器限速linux路由器

2010-04-07 13:05:57

2025-02-08 08:21:48

Java排序Spring

2024-09-30 09:56:59

點贊
收藏

51CTO技術棧公眾號

欧美在线免费观看| 日韩激情av在线免费观看| 正在播放亚洲| www国产在线| 伊人成人在线| 国产亚洲欧美另类中文| 国产永久免费网站| 91九色在线播放| 久久九九国产精品| 99精品欧美一区二区三区| 亚洲成熟少妇视频在线观看| 中文字幕一区二区三区乱码图片 | 992kp快乐看片永久免费网址| 麻豆传媒在线观看| 99riav一区二区三区| 国产美女精品视频| 国产成人无码精品久在线观看| 日韩一级毛片| 亚洲经典中文字幕| 性生活一级大片| 搜成人激情视频| 亚洲一二三四在线| 偷拍盗摄高潮叫床对白清晰| 男人av在线| 国产成人精品午夜视频免费| 国产精品偷伦视频免费观看国产| 成年人视频在线免费看| 亚洲欧美亚洲| 久久亚洲精品成人| 污污视频网站在线免费观看| 六月丁香久久丫| 日韩一二三区不卡| 91小视频在线播放| 一区在线影院| 一本大道久久a久久精二百| 男人天堂a在线| a级毛片免费观看在线| 欧美国产精品中文字幕| 久久婷婷开心| 欧美天堂在线视频| 国v精品久久久网| 成人国产在线激情| 中文字幕观看在线| 天堂一区二区在线免费观看| 69av在线播放| 亚洲精品国产精品乱码| 国产精品大片免费观看| 欧美精品生活片| 四虎884aa成人精品| 91一区在线| 爽爽爽爽爽爽爽成人免费观看| 日本乱子伦xxxx| 国产精品免费大片| 在线亚洲国产精品网| 久久久无码人妻精品一区| 日本一道高清一区二区三区| 亚洲成在人线av| 艳妇乳肉豪妇荡乳xxx| 成人福利免费在线观看| 精品国产人成亚洲区| 国产在线观看免费播放| 国产精品videossex| 亚洲国产免费av| 亚洲一区二区三区无码久久| 欧美日韩破处| 亚洲跨种族黑人xxx| 中文字幕av网址| av一区二区在线观看| 中文字幕精品—区二区| 日韩亚洲欧美中文字幕| 一本到12不卡视频在线dvd| 欧美肥婆姓交大片| 国产成人亚洲欧洲在线| 亚洲欧美久久| 国产精品一区专区欧美日韩| 国产口爆吞精一区二区| 国产91在线观看| 久久伊人一区二区| 成人高潮成人免费观看| 亚洲婷婷在线视频| 日本黄色片一级片| 亚洲一区站长工具| 欧美男女性生活在线直播观看| 欧美一级视频在线| 精品久久ai电影| 亚洲色图美腿丝袜| 日韩在线不卡av| 亚洲国产第一| 国产精品丝袜白浆摸在线| 99riav国产| 99免费精品在线观看| 欧美一区二区在线| 国产精品实拍| 日韩欧美亚洲一二三区| 中文字幕22页| 哺乳挤奶一区二区三区免费看| 亚洲国产精品99久久| 欧美日韩中文字幕视频| 欧美日韩网址| 国产精品aaa| 亚洲a视频在线观看| 久久久久国产精品麻豆| 日本一区二区免费高清视频| 日本不卡网站| 欧美精品一二三| 国产精品无码专区| 91一区二区三区四区| 91成人福利在线| 99在线观看免费| 久久久天堂av| 人人妻人人澡人人爽欧美一区| 澳门成人av网| 精品嫩草影院久久| 国产第一页精品| 极品尤物久久久av免费看| 97免费在线视频| 国产三级午夜理伦三级| 国产亚洲欧美一区在线观看| 大陆av在线播放| 亚洲伊人精品酒店| 一本一道久久a久久精品逆3p| 国产精品50页| 精品在线播放免费| 欧美一区1区三区3区公司| av电影院在线看| 51久久夜色精品国产麻豆| 在线免费看黄视频| 亚洲精选在线| 国产欧美一区二区视频| 18视频在线观看| 在线播放中文字幕一区| 精品亚洲aⅴ无码一区二区三区| 99亚洲视频| 91视频网页| 国产原创在线观看| 欧美日本在线看| 性の欲びの女javhd| 久久综合婷婷| 欧美日韩国产高清视频| 美女露胸视频在线观看| 亚洲第一福利网| 国产在线视频你懂的| 国产精品影视在线| 三级在线免费观看| 日韩在线观看中文字幕| 久久综合88中文色鬼| 国产精品一区二区黑人巨大| 国产精品久久久久影院亚瑟| 在线观看亚洲色图| 日韩国产一区| 91久久国产婷婷一区二区| 国产区在线观看| 日韩精品中文字幕在线一区| 欧美日韩大片在线观看| 国产91色综合久久免费分享| 国产一区二区三区乱码| 激情小说亚洲图片| 欧美在线精品免播放器视频| 免费人成在线观看网站| 欧美在线观看18| 婷婷国产成人精品视频| 韩国毛片一区二区三区| 国产高潮呻吟久久久| 在线观看欧美| 欧美超级乱淫片喷水| 亚洲精品久久久久久无码色欲四季 | 51国偷自产一区二区三区的来源| 国产在线高潮| 欧美刺激脚交jootjob| 免费在线视频观看| 99久久免费国产| 亚洲精品高清无码视频| 欧美激情理论| 波多野结衣成人在线| cao在线视频| 亚洲视频在线观看视频| 一级片一区二区三区| 一级日本不卡的影视| 中国av免费看| 久久成人免费电影| 欧美一区二区视频在线播放| 中国av一区| 成人www视频在线观看| а√天堂8资源在线| 亚洲一级黄色片| 国产熟女精品视频| 福利二区91精品bt7086| 夫妇露脸对白88av| 成人一区二区视频| 亚洲国产精品毛片av不卡在线| 国产精品精品| 久久99国产精品99久久| www.久久久久爱免| 久久免费成人精品视频| 北岛玲一区二区三区| 日韩欧美亚洲另类制服综合在线| 国产美女激情视频| 亚洲另类色综合网站| 91中文字幕永久在线| 国产麻豆视频精品| 日韩一级片播放| 欧美私人啪啪vps| 日韩欧美一区二区三区四区| 中文字幕一区二区三区中文字幕| 国产成人97精品免费看片| 久久香蕉av| 色婷婷综合久久久久| 免费在线超碰| 日韩av在线免费| 国产aⅴ爽av久久久久成人| 91黄色免费观看| 日本亚洲色大成网站www久久| 国产精品久久久爽爽爽麻豆色哟哟 | 青青青国产在线| 亚洲一级在线观看| 国产精品免费在线视频| 久久先锋资源网| 日韩精品视频一区二区| 国产一区二区毛片| 182午夜在线观看| 久久精品麻豆| 无罩大乳的熟妇正在播放| 女人天堂亚洲aⅴ在线观看| 亚洲精品中文字幕在线| 性欧美lx╳lx╳| 国产九色精品| 亚洲欧洲国产精品一区| 91精品国产自产在线老师啪 | 91在线无精精品一区二区| 久久天堂av| 国产福利精品av综合导导航| 咪咪网在线视频| 性色av一区二区三区| 日韩精品卡一| 欧美精品少妇videofree| 国产视频一区二区| 久热精品视频在线观看一区| xxxxx日韩| 色噜噜久久综合伊人一本| 大片免费播放在线视频| 亚洲欧洲偷拍精品| 可以在线观看的av| 亚洲欧美日韩成人| 精品无人乱码| 亚洲视频国产视频| 国产在线一在线二| 在线播放国产精品| av在线中文| 日韩在线www| 亚洲麻豆精品| 久久久91精品国产| 国产写真视频在线观看| 欧美巨乳在线观看| 伊人春色在线观看| 国模精品系列视频| 国产伦子伦对白在线播放观看| 欧美自拍大量在线观看| 欧美大胆成人| 国产精品入口免费视频一| 欧美aaaaaa| 51国偷自产一区二区三区| www.久久东京| 久久精品国产一区二区三区日韩| 亚洲影院天堂中文av色| 香蕉久久夜色| 亚洲国产老妈| av在线播放亚洲| 久久久精品网| 亚洲精品国产一区二区三区| 国产99久久久久久免费看农村| aaa黄色大片| 久久久天堂av| 性欧美疯狂猛交69hd| 亚洲一区二区三区四区五区中文| 人人干人人干人人干| 色婷婷一区二区| 在线观看日批视频| 精品久久久久久亚洲综合网| 精品亚洲成a人片在线观看| y97精品国产97久久久久久| 国产嫩草在线视频| 国产精品18久久久久久麻辣| 精品麻豆剧传媒av国产九九九| 国产精品久久7| av永久不卡| 青青在线免费观看| 青草国产精品久久久久久| 精品国产一二区| 国产婷婷一区二区| 久久久久久蜜桃| 日本电影亚洲天堂一区| 不卡视频免费在线观看| 亚洲人成人99网站| 日本在线观看大片免费视频| 国产91在线视频| 2020国产精品极品色在线观看| 欧洲亚洲一区二区| 欧美日韩国产高清| 日韩免费高清在线| 成人一区二区视频| 日日操免费视频| 欧美日韩中文字幕| 99产精品成人啪免费网站| 亚洲欧美激情在线视频| 日韩三级电影视频| 成人妇女淫片aaaa视频| 国产一区二区三区电影在线观看 | 精品国产凹凸成av人网站| 国产视频第一页在线观看| 欧美激情精品久久久久久变态| www.成人在线视频| 久久精品五月婷婷| 欧美/亚洲一区| 国内外成人免费在线视频| 91尤物视频在线观看| 欧美黄色免费看| 欧美久久久久久蜜桃| 韩国三级在线观看久| 久久人人看视频| 国产成人免费av一区二区午夜| 日韩亚洲欧美精品| 久久久蜜桃一区二区人| 少妇精品无码一区二区三区| 一区二区三区毛片| 国产乱码一区二区| 日韩视频中文字幕| 欧美天堂在线| 深夜福利成人| 日韩电影免费在线| 无码少妇精品一区二区免费动态| 婷婷成人综合网| 人妻妺妺窝人体色www聚色窝 | 日韩在线免费| 麻豆91蜜桃| 日韩一级精品| 手机在线成人av| 亚洲成在人线免费| 欧美自拍偷拍一区二区| 久久久这里只有精品视频| www.爱久久| 国产人妻777人伦精品hd| 成人高清免费观看| 日本在线视频免费| 日韩风俗一区 二区| 欧美xxxhd| 欧美日韩亚洲综合一区二区三区激情在线| 日韩香蕉视频| 日本黄色网址大全| 日韩欧美中文免费| jizz日韩| 成人免费午夜电影| 一区二区三区毛片免费| 妖精视频在线观看| 亚洲国产视频网站| 香蕉视频免费看| 国产成人精品视频| 日韩欧美精品综合| 美女被艹视频网站| 亚洲成人在线免费| 国产在线中文字幕| 国产主播精品在线| 今天的高清视频免费播放成人| 亚洲国产精品自拍视频| 色综合色狠狠综合色| 91在线品视觉盛宴免费| 亚洲最大的av网站| 亚洲激情在线| 波多野在线播放| 欧美精品日日鲁夜夜添| 牛牛电影国产一区二区| 精品视频第一区| 美国一区二区三区在线播放| 久热这里有精品| 日韩精品亚洲精品| 99只有精品| 国产免费一区二区视频| 久久久久久久久97黄色工厂| 91黄色在线视频| 久久理论片午夜琪琪电影网| 欧美一站二站| 中文字幕在线观看视频www| 欧美小视频在线| 黄网站免费在线观看| 国产精品我不卡| 麻豆高清免费国产一区| 国产在线视频99| 日韩在线精品视频| 亚洲日本va| 日韩欧美国产片| 亚洲成人一二三| 免费av在线| 久久涩涩网站| 国产91在线观看| 国产精品51麻豆cm传媒| 久久免费高清视频| 五月久久久综合一区二区小说| 又黄又爽的网站| 日韩一区国产二区欧美三区| av高清不卡| 国产精品一色哟哟|