天天看點

Scala 深入淺出實戰經典 第66講:Scala并發程式設計實戰初體驗

王家林親授《DT大資料夢工廠》大資料實戰視訊 Scala 深入淺出實戰經典(1-87講)完整視訊、PPT、代碼下載下傳:

百度雲盤:http://pan.baidu.com/s/1c0noOt6

騰訊微雲:http://url.cn/TnGbdC

360雲盤:http://yunpan.cn/cQ4c2UALDjSKy 通路密碼 45e2

洋芋:http://www.tudou.com/programs/view/j_kmot9uBb0/

優酷:http://v.youku.com/v_show/id_XMTI5MTgwMDAxNg==.html?from=s1.8-1-1.2

愛奇藝:http://www.iqiyi.com/w_19rru5bi79.html#vfrm=2-3-0-1

騰訊視訊:http://v.qq.com/boke/page/b/0/5/b0160il3wj5.html

技術愛好者尤其是大資料愛好者 可以加DT大資料夢工廠的qq群

DT大資料夢工廠① :462923555

DT大資料夢工廠②:437123764

DT大資料夢工廠③ :418110145

微信公衆賬号: DT_Spark

王家林老師微信号: 18610086859

王家林老師QQ: 1740415547

王家林老師郵箱: [email protected]

本視訊由王家林老師, 親自講解, 完全通過代碼實戰把您帶人大資料的時代.

package com.parllay.scala.actor

/**

* Created by richard on 15-8-25.

* 第66講:Scala并發程式設計實戰初體驗

*/

object Hello_Actor {

/**

* Scala語言有很多優點,比如簡潔、強大的表現力等等。但我最關注的,是它在并發程式設計方面的優勢。

Scala通過強調對象的不變性 以及使用基于事件的模型進行線程間通信 使得實作并發應用變得簡單。

不變對象

并發程式設計之是以這麼困難,很大一個原因在于對象的可變性。

要在充斥着大量可變對象的程式裡面實作安全并發,

需要非常繁瑣以及複雜易錯的同步操作來保證狀态更新的同步。

比如下面這段代碼(java的例子),可能你會認為它已經是線程安全的了,

因為所有的方法都已經被同步。

Java代碼 收藏代碼

class Account {

private int balance;

synchronized public int getBalance() {

return balance;

}

synchronized public void incrementBalance() {

balance++;

}

但是問題來了,當順序調用這兩個方法的時候,比如:

account.incrementBalance();

account.getBalance();

這時并不是線程安全的,在第一個方法調用結束之後,

可能會被其它線程擷取對象的鎖,修改account的balance。

在指令式程式設計語言裡面,指令查詢分離是一個普遍使用的原則。意即:

一個方法要麼進行一次指令(執行一個操作,通常會修改狀态),

要麼進行一次查詢(傳回一些狀态, 但并不修改狀态),而不應該同時執行指令以及查詢。

從面向對象的角度看,這是一個良好的設計;但從并發程式設計的角度看,

它卻帶來了一些問題,使得并發程式設計實作更加困難。上面就是一個很好的例子。

要使得上面這段代碼變得線程安全,可以通過破壞指令查詢分離原則來實作:

synchronized public int incrementAndGetBalance() {

balance++;

return balance;

從上面的例子看到,在可變對象的環境中實作并發程式設計是困難的。而不變對象,

意即線程安全的對象,使得我們不必擔心共享對象會被多個線程同時修改而無法保持它的正确性:

因為它本身就不可修改。我們可以把不變對象很放心地扔到多線程環境中,任意使用。

問題又來了,如果要“修改狀态”怎麼辦?很簡單,建立一個新的對象。還是上面那個例子,

我們把它修改成一個Scala的不變對象類。并在伴生對象裡面實作increment方法,

此方法會傳回一個新的account對象,balance值為原有對象的值加1所得。

class Account (val balance: Integer) {

def getBalance() = balance

object Account {

def increment(account: Account): Account {

new Account(account.getBalance() + 1)

}

通過強調不變對象的使用,并發程式設計變得簡單了很多。

Actor

傳統的并發是通過線程(thread)來實作的。在傳統的并發模型中,程式被分成若幹份同時執行的任務,

并且所有任務都對一塊共享的記憶體進行操作。在傳統的并發模型會引起競争問題,

可以采取鎖機制避免競争問題,但同時這可能帶來死鎖等問題。

Actor模型是另一種不同的并發模型,它很好地解決了在傳統并發模型中競争和死鎖等問題。

我們可以把一個由actor模型實作的并發程式看成是一個星系一樣,星系裡面有很多星球,

每個星球都是一個actor,星球之間不共享任何資源,但是它們之間有通道來互相傳遞資訊。

每個星球(actor)都有一個信箱來接受來自其它星球的任意資訊,它會按照資訊接收的順序來處理,

處理完一個資訊然後接着處理下一個資訊。可以按照資訊類型來觸發不同的行為。

同時,每個星球(actor)可以異步地(也可以同步,但不是這裡談論的重點)向其它任意星球發送任意消息,

就是說,它發送消息之後不會等待傳回資訊而是直接執行接下來的操作。

下面是一個Actor的例子:

import scala.actors.Actor

import scala.actors.Actor._

case class Increment(amount: Int)

case class Balance

class Account extends Actor {

var balance: Int = 0;

def act() = {

while (true) {

receive {

case Increment(amount) =>

balance += amount

case Balance =>

println("Balance is " + balance)

exit()

}

}

我們可以看到,程式裡面定義兩種不同的消息類型:Increment和Balance。Account是一個Actor,

它跟外界的互動都是通過消息傳遞來實作:不論是increment,還是擷取balance都是通過消息的方式來實作。

當接受到不同的消息時,它會執行不同的行為。

我們也可以看到,Account的内部狀态完全是自己控制的,接收到的消息是順序執行的,

是以我們不需要擔心競争問題。

小結

Scala就是這樣,通過“使用基于事件的模型進行線程間通信”,并且“把不變對象作為消息進行傳遞”來實作一個并發程式設計模型。

*/

長期招聘java,有找工作可以聯系我,微信:caozhenhua1563