亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

并發(fā)學(xué)習(xí)筆記(2)

saucxs / 1419人閱讀

摘要:當(dāng)其他線程調(diào)用時,它們被阻塞,直到第一個線程釋放鎖對象。包關(guān)于獲取這個鎖如果鎖同時被另一個線程擁有則發(fā)生阻塞。所以必須確保沒有其他線程再檢查余額和轉(zhuǎn)賬活動之間修改金額。方法添加一個線程到等待集中,方法解除等待線程的阻塞狀態(tài)。

避免代碼塊受到并發(fā)訪問的干擾

java語言提供了兩種機(jī)制實(shí)現(xiàn)這種功能

Synchonized 關(guān)鍵字(調(diào)用對象內(nèi)部的鎖)
synchronized關(guān)鍵字自動提供一個鎖以及相關(guān)的條件

引入了ReentrantLock類。(顯示鎖)

更好: JUC框架為這些基礎(chǔ)機(jī)制提供了獨(dú)立的類: 線程池,或者高級一點(diǎn)專門做并發(fā)的工具的支持

ReentrantLock類 - 鎖 Lock 與synchronized 區(qū)別

Lock 不是Java語言內(nèi)置(compared to synchronized),Lock是一個類,通過這個類可以實(shí)現(xiàn)同步訪問;

Lock 和 synchronized有一點(diǎn)非常大的不同,采用synchronized不需要用戶去手動釋放鎖,當(dāng)synchronized方法或者synchronized代碼塊執(zhí)行完之后,系統(tǒng)會自動讓現(xiàn)場釋放對鎖的占用,而Lock必須要用戶手動釋放,如果沒有主動釋放鎖,將會產(chǎn)生死鎖。 + Lock優(yōu)缺點(diǎn)

Lock優(yōu)缺點(diǎn)(compared to Synchronized)

Lock 能完成synchronized所實(shí)現(xiàn)的所有功能,而且比synchronized更好的性能。而且沒有synchronized簡潔。
但是:
1. 如果希望當(dāng)獲取鎖時,有一個等待時間,不會無限期等待下去。
2. 希望當(dāng)獲取不到鎖時,能夠響應(yīng)中斷
3. 當(dāng)讀多,寫少的應(yīng)用時,希望提高性能
4. 獲取不到鎖時,立即返回 false。獲取到鎖時返回 true。

用ReentrantLock 保護(hù)代碼塊的基本結(jié)構(gòu)如下:

myLock.lock();
try{
   critical section
}
finally{
    myLock.unlock(); // 把解鎖語句放在finally子句內(nèi)是至關(guān)重要的。如果在臨界區(qū)的代碼拋異常,鎖必須被釋放。否則,其他線程將永遠(yuǎn)阻塞。
}

用鎖來保護(hù)Bank類的transfer方法

public class Bank
{
    private Lock bankLock = new ReentrantLock();
    public void transfer(int from, int to, int amount){
        bankLock.lock();
        try{
            accounts[from] -= amount;
            account[to] += amount; 
        }
        finally{
            bankLock.unlock();
        }
    }
}

這個結(jié)構(gòu)確保任何時刻只有一個線程進(jìn)入臨界區(qū),一旦一個線程封鎖了鎖對象,其他任何線程都無法通過lock語句。當(dāng)其他線程調(diào)用lock時,它們被阻塞,直到第一個線程釋放鎖對象。

JUC包關(guān)于Lock
java.util.concurrent.locks.Lock
- void lock()
獲取這個鎖;如果鎖同時被另一個線程擁有則發(fā)生阻塞。
- void unlock()
釋放這個鎖
java.util.concurrent.locks.ReentrantLock
- ReentrantLock()
構(gòu)建一個可以被用來保護(hù)臨界區(qū)的可重入鎖
- ReentrantLock(boolean fair)
構(gòu)建一個帶有公平策略的鎖。一個公平鎖偏愛等待時間最長的鎖,但是公平的保證會導(dǎo)致大大降低性能。

條件對象

通常線程進(jìn)入臨界區(qū),卻發(fā)現(xiàn)在某一條件滿足之后它才能執(zhí)行。要使用一個條件對象來管理那些已經(jīng)獲得了一個鎖但是不能做擁有工作的線程。
比如銀行的模擬程序。我們避免沒有足夠資金的賬戶作為轉(zhuǎn)出賬戶. 如下的代碼是不可以的,代碼有可能在transfer方法之前被中斷,在線程在此運(yùn)行前,賬戶余額可能已經(jīng)低于提款金額了。

java if(bank.getBalance(from) >= amount)
    // thread might be deactivated at this point
    bank.transfer(from,to,amount);

所以必須確保沒有其他線程再檢查余額和轉(zhuǎn)賬活動之間修改金額。通過鎖來保護(hù)檢查與轉(zhuǎn)賬動作的原子性,來做到這一點(diǎn):

javapublic void transfer(int from, int to, int amount){
    backLock.lock();
    try{
        while(accounts[from] < amount){
            // wait
        }
        // transfer funds;
    }
    finally{
        bankLock.unlock();
    }
}

當(dāng)賬戶沒有足夠的余額的時候,應(yīng)該做什么?當(dāng)前線程陷入wait until 另一個線程向賬戶注入了資金。但是鎖的排他性導(dǎo)致其他線程沒有進(jìn)行存款操作的機(jī)會。這就是為什么需要調(diào)節(jié)對象的原因。

一個鎖對象可以有一個或者多個相關(guān)的條件對象。可以用newCondition方法獲得一個條件對象。

java class Bank{
    private Condition sufficientFunds;
    public Bank(){
        sufficientFunds = bankLock.newCondition();
    }
 }

如果transfer方法發(fā)現(xiàn)余額不足,就可以調(diào)用sufficientFunds.await() 當(dāng)前線程被阻塞,并放棄了鎖;一旦一個線程調(diào)用了await(),它進(jìn)入了該條件的等待集(進(jìn)入等待狀態(tài))。當(dāng)鎖可用時,該線程不能馬上解除阻塞,相反,它仍然處于阻塞狀態(tài),也就是自己不能激活自己,需要另一個線程調(diào)用同一條件的signalAll方法為止。而signalAll方法僅僅是通知正在等待的線程:此時有可能已經(jīng)滿足條件,值得再次去檢查該條件。
所以正確的代碼是:

javapublic void transfer(int from, int to, int amount){
    backLock.lock();
    try{
        while(accounts[from] < amount)
           sufficientFunds.await();
        // transfer funds;
        ...
       sufficientFunds.signalAll();
    }
    finally{
        bankLock.unlock();
    }
}

Condition newCondition()
返回一個與該鎖相關(guān)的條件對象。
java.util.concurrent.locks.Condition

void await()
將該線程放到條件的等待集中

void signalAll()
解除該條件的等待集中的所有線程的阻塞狀態(tài)

void signal()
從該條件的等待集中隨機(jī)地選擇一個線程,解除其阻塞狀態(tài)

總結(jié)一下有關(guān)鎖(外部鎖)和條件的關(guān)鍵之處:
- 鎖用來保護(hù)代碼片段,任何時刻只能有一個線程執(zhí)行被保護(hù)的代碼
- 鎖可以管理試圖進(jìn)入被保護(hù)代碼段的線程
- 鎖可以擁有一個或多個相關(guān)的條件對象
- 每個條件對象管理那些已經(jīng)進(jìn)入被保護(hù)代碼段但還不能運(yùn)行的先。

Java Synchronized keywords

synchronized 是java的關(guān)鍵字,也就是說是java語言內(nèi)置的特性, 是托管給JVM執(zhí)行的。
java的每一個對象都有一個內(nèi)部鎖。如果一個方法用synchronized聲明,那么對象的鎖將保護(hù)整個方法。namely,要調(diào)用該方法線程必須獲得內(nèi)部的對象鎖。通過使用synchonized 塊可以避免競爭條件;synchonized 修飾的同步代碼塊確保了一次只能一個線程執(zhí)行同步的代碼塊。所有其它試圖進(jìn)入同步塊的線程都會阻塞,直到同步塊里面的線程退出這個塊。

用Synchronized保護(hù)代碼塊的基本結(jié)構(gòu)如下:

public synchronized void method(){
...
}

synchronized鎖定的是調(diào)用這個同步方法的對象。 namely 當(dāng)一個對象P1在不同的線程中執(zhí)行這個同步方法時,不同的線程會形成互斥,達(dá)到同步的效果。但是這個對象所屬的類的另一個對象P2卻能調(diào)用這個被加了synchonized的方法。
上述代碼等同于

public void method(){
synchronized(this){...}
}

this 指的是調(diào)用這個方法的對象,可見同步方法實(shí)質(zhì)上是將synchronized作用于object reference -- 拿到了P1對象鎖的線程,才能調(diào)用調(diào)用P1的同步方法。

javaclass Bank{
    private double[] accounts;
    public synchronized void tranfer(int from, int to, int amount) throws InterruptedException{
        while(accounts[from] < amount)
            wait();// wait on intrinsic object lock"s single condition
        accounts[from] -= amount;
        accounts[to] += amount;
        notifyAll(); // notify all threads waiting on the condition
    }
}

可以看到synchronized關(guān)鍵字來編寫代碼要簡潔的多。要理解這一代碼,再一次重申:每一個對象有一個內(nèi)部鎖,并且該鎖有一個內(nèi)部條件。 由內(nèi)部鎖來管理那些試圖進(jìn)入synchronized方法的線程,由條件來管理那些調(diào)用wait的線程。
java的 synchronized 關(guān)鍵字能夠作為函數(shù)的修飾符,也可作為函數(shù)內(nèi)的語句,也就是平時說的同步方法和同步語句塊.

而無論 synchronized 關(guān)鍵字是加在了方法上還是對象上,他取得的鎖都是對象,而不是把一段代碼或者函數(shù)當(dāng)做鎖; 每個對象只有一個鎖(lock)與之關(guān)聯(lián)。 實(shí)現(xiàn)同步是要很大的系統(tǒng)開銷作為代價的,甚至可能造成死鎖,所以要盡量不免無謂的同步控制。

相關(guān)條件

內(nèi)部對象鎖只有一個相關(guān)條件。wait方法添加一個線程到等待集中,notifyAll/notify方法解除等待線程的阻塞狀態(tài)。調(diào)用wait or notifyall等價于

intrinsicCondition.await()
intrinsicCondition.signalAll()
    public synchronized void transfer(int from, int to, double amount) throws InterruptedException{
        while(accounts[from] < amount){
            wait();
        }
        System.out.print(Thread.currentThread());
        accounts[from] -= amount;
        accounts[to] += amount;
        notifyAll();
    }

java.lang.Object
- void notifyAll()
解除那些在該對象上調(diào)用wait方法的線程的阻塞狀態(tài)
java.util.concurrent.locks.Condition
- void await()
將該線程放到條件的等待集中
- void signalAll()
解除該條件的等待集中的所有線程的阻塞狀態(tài)
- void signal()
從該條件的等待集中隨機(jī)地選擇一個線程,解除其阻塞狀態(tài)

synchorinzed(缺陷)
- 不能中斷一個正在試圖獲得鎖的線程; 

如果一個代碼塊被synchronized修飾了,當(dāng)一個線程獲取了對應(yīng)的鎖,并執(zhí)行該代碼塊時,其他線程便只能一直等待,等待獲取鎖的線程釋放鎖,而這里獲取鎖的線程釋放鎖只會有兩種情況:

  1)獲取鎖的線程執(zhí)行完了該代碼塊,然后線程釋放對鎖的占有;
  2)線程執(zhí)行發(fā)生異常,此時 JVM 會讓線程自動釋放鎖。

  那么如果這個獲取鎖的線程由于要等待 IO 或者其他原因(比如調(diào)用sleep方法)被阻塞了,但是又沒有釋放鎖,其他線程便只能干巴巴地等待,試想一下,這多么影響程序執(zhí)行效率。

- 試圖獲得鎖時不能設(shè)定超時;

- 每個鎖僅有單一的條件,可能不夠的;
總結(jié)

在代碼中應(yīng)該使用哪一種呢? Lock 和 Condition對象還是同步方法?
下面是Core java的一些建議:

最好既不是用Lock/Condition 也不是用synchonized關(guān)鍵字。 在許多情況下可以使用JUC包中的一種機(jī)制,它會為你處理所有加鎖.

如果synchronized關(guān)鍵字適合你的程序,那么盡量使用它,這樣可以減少編寫的代碼數(shù)量,減少出錯幾率。

如果特別需要Lock/Condition結(jié)果提供的獨(dú)有特性,才使用Lock/Condition

5.18

阻塞隊(duì)列

對于許多線程問題,可以通過使用一個或多個隊(duì)列以優(yōu)雅且安全的方式將其形式化。比如生產(chǎn)者線程向隊(duì)列插入元素,消費(fèi)者線程則取出它們。使用隊(duì)列,可以安全地從一個線程向另一個線程傳遞數(shù)據(jù)。

阻塞隊(duì)列是一種比lock, synchonized更高級的管理同步的方法。

具體實(shí)現(xiàn):
先定義一個BlockingQueue,隊(duì)列放共享的資源,然后多個線程取或者存然后直接調(diào)用他的函數(shù)放入和取出元素就行了.

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/65300.html

相關(guān)文章

  • Java 并發(fā)學(xué)習(xí)筆記(二)

    摘要:請參看前一篇文章并發(fā)學(xué)習(xí)筆記一原子性可見性有序性問題六等待通知機(jī)制什么是等待通知機(jī)制當(dāng)線程不滿足某個條件,則進(jìn)入等待狀態(tài)如果線程滿足要求的某個條件后,則通知等待的線程重新執(zhí)行。經(jīng)極客時間并發(fā)編程實(shí)戰(zhàn)專欄內(nèi)容學(xué)習(xí)整理 請參看前一篇文章:Java 并發(fā)學(xué)習(xí)筆記(一)——原子性、可見性、有序性問題 六、等待—通知機(jī)制 什么是等待通知—機(jī)制?當(dāng)線程不滿足某個條件,則進(jìn)入等待狀態(tài);如果線程滿足要...

    zgbgx 評論0 收藏0
  • Java 并發(fā)學(xué)習(xí)筆記(一)——原子性、可見性、有序性問題

    摘要:最后,總結(jié)一下,導(dǎo)致并發(fā)問題的三個源頭分別是原子性一個線程在執(zhí)行的過程當(dāng)中不被中斷??梢娦砸粋€線程修改了共享變量,另一個線程能夠馬上看到,就叫做可見性。 計(jì)算機(jī)的 CPU、內(nèi)存、I/O 設(shè)備的速度一直存在較大的差異,依次是 CPU > 內(nèi)存 > I/O 設(shè)備,為了權(quán)衡這三者的速度差異,主要提出了三種解決辦法: CPU 增加了緩存,均衡和內(nèi)存的速度差異 發(fā)明了進(jìn)程、線程,分時復(fù)用 CP...

    Chao 評論0 收藏0
  • 并發(fā)學(xué)習(xí)筆記 (6)

    摘要:每個通過網(wǎng)絡(luò)到達(dá)服務(wù)器的連接都被包裝成一個任務(wù)并且傳遞給線程池。線程池的線程會并發(fā)的處理連接上的請求。用線程池控制線程數(shù)量,其他線程排隊(duì)等候。實(shí)現(xiàn)包,線程池頂級接口是但是嚴(yán)格意義講并不是一個線程。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求。 tutorial site1tutorial site2 一個問題: 每啟動一個新線程都會有相應(yīng)的性能開銷(涉及到OS的交互:創(chuàng)建線程,銷毀線程...

    superw 評論0 收藏0
  • 并發(fā)學(xué)習(xí)筆記 (4)

    摘要:不剝奪條件進(jìn)程已獲得的資源,在末使用完之前,不能強(qiáng)行剝奪。如果能確保所有的線程都是按照相同的順序獲得鎖,那么死鎖就不會發(fā)生。按照順序加鎖是一種有效的死鎖預(yù)防機(jī)制。這種機(jī)制存在一個問題,在中不能對同步塊設(shè)置超時時間。 [tutorial site][1] 死鎖 deadlock 死鎖是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,因競爭資源而造成的一種互相等待的現(xiàn)在,若無外力作用,它們都無法推...

    shiguibiao 評論0 收藏0
  • Go語言核心36講(Go語言實(shí)戰(zhàn)與應(yīng)用十二)--學(xué)習(xí)筆記

    摘要:除此之外,把并發(fā)安全字典封裝在一個結(jié)構(gòu)體類型中,往往是一個很好的選擇。請看下面的代碼如上所示,我編寫了一個名為的結(jié)構(gòu)體類型,它代表了鍵類型為值類型為的并發(fā)安全字典。在這個結(jié)構(gòu)體類型中,只有一個類型的字段。34 | 并發(fā)安全字典sync.Map (上)我們今天再來講一個并發(fā)安全的高級數(shù)據(jù)結(jié)構(gòu):sync.Map。眾所周知,Go 語言自帶的字典類型map并不是并發(fā)安全的。前導(dǎo)知識:并發(fā)安全字典誕生...

    不知名網(wǎng)友 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<