小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

多線程調(diào)優(yōu)經(jīng)驗-并發(fā)控制方法

 西北望msm66g9f 2020-02-21

寫在前面


◆ ◆ ◆ ◆


并行程序開發(fā)將不可避免地要涉及多線程、多任務(wù)間的寫作和數(shù)據(jù)共享等問題。在JDK中,提供了多種途徑實現(xiàn)多線程間的并發(fā)控制。常用的方法有:內(nèi)部鎖、重入鎖、讀寫鎖、信號量等

Java內(nèi)存模型與volatile


◆ ◆ ◆ ◆


Java中每一個線程有一塊工作內(nèi)存區(qū),其中存放著被所有線程共享的主內(nèi)存中的變量的值的拷貝。當(dāng)線程執(zhí)行時,它在自己的工作內(nèi)存中操作著這些變量。為了存取一個共享的變量,一個線程通常先獲取鎖定并且清除它的工作內(nèi)存區(qū),這保證該共享變量從所有線程的共享內(nèi)存區(qū)正確地裝入到線程的工作內(nèi)存區(qū),當(dāng)線程解鎖時保證該工作內(nèi)存區(qū)中變量的值寫回到共享內(nèi)存中。

一個線程可以執(zhí)行的操作有使用(user),賦值(assign),裝載(load),存儲(store),鎖定(lock),解鎖(unlock)。而主內(nèi)存可以執(zhí)行的操作有讀(read),寫(write),鎖定(lock),解鎖(unlock),每一個操作都是原子的。如下圖:

當(dāng)一個線程使用某一個變量時,不論程序是否正確地使用線程同步操作,它獲取的值一定時由它本身或者其他線程存儲到變量中的值。例如,如果兩個線程把不同值或者對象引用存儲到同一個共享變量中,那么該變量的值要么是這個線程的,要么是另一個線程的,共享變量的值不會由兩個線程的引用值組合而成(除long,double外)。

一個變量是Java程序可以存取的一個地址,它不僅包括基本類型變量、引用類型變量,還包括數(shù)據(jù)類型變量。保存在主內(nèi)存區(qū)的變量可以被所有線程共享,但一個線程存取另一個 線程的參數(shù)或者局部變量是不可能的。

由于每個線程都有自己的工作內(nèi)存區(qū),因此當(dāng)一個線程改變自己的工作內(nèi)存中的數(shù)據(jù)時,對其他線程來說,可能是不可見的。因此,可以使用volatile關(guān)鍵字迫使所有線程均讀寫主內(nèi)存中的對應(yīng)變量,從而使得volatile變量在多線程間可見。

聲明volatile的變量可以做到如下保證:

  1. 其他線程對變量的修改,可以即時反應(yīng)在當(dāng)前線程中。

  2. 確保當(dāng)前線程對volatile變量的修改,能即時寫回共享主內(nèi)存中,并被其他線程所見。

  3. 使用volatile聲明的變量,編譯器會保證其有序性。

同步關(guān)鍵字synchronized


◆ ◆ ◆ ◆


同步關(guān)鍵字synchronized使用簡潔,代碼可維護(hù)性好。在JDK6中,性能也比早期的JDK由很大改進(jìn),如果可以滿足程序要求,可以首先考慮這種同步方式。

synchronized最常用的方法是鎖定一個對象的方法;也可以同步塊,與同步方法相比,可以更為精確地控制代碼的范圍,有利于鎖的快進(jìn)快出,提高吞吐量。

當(dāng)synchronized用于static函數(shù)時,相當(dāng)于將鎖加到當(dāng)前Class對象上,因此,所有對該方法的調(diào)用,都必須獲得Class對象的鎖。

ReentrantLock重入鎖


◆ ◆ ◆ ◆


ReentrantLock比內(nèi)部鎖synchronized擁有更強大的功能,它可以中斷,可定時。JDK5中,在高并發(fā)的情況下,它比synchronized有明顯的性能優(yōu)勢。在JDK6中,由于JVM的優(yōu)化,兩者差別不是很大。

ReentrantLock還提供了公平和非公平的兩種鎖。公平鎖可以保證鎖的等待隊列中的各個線程是公平的,不會出現(xiàn)插隊的情況,對鎖的獲取總是先進(jìn)先出,而非公平的就不做這個保證,申請鎖的線程可以插隊。公平鎖的實現(xiàn)代價比非公平的大,因此從性能上,非公平鎖的性能要好得多。因此若無特殊的需求,應(yīng)該優(yōu)先考慮非公平鎖。

使用ReentrantLock時,一定要牢記,在程序最后釋放鎖。一般釋放鎖的代碼要寫在finally里,否則如果程序出現(xiàn)異常,鎖將無法釋放了。相比synchronized,JVM總是會在最后自動釋放synchronized鎖。

ReadWriteLock讀寫鎖


◆ ◆ ◆ ◆


ReadWriteLock讀寫鎖是JDK5中提供的讀寫分離鎖。讀寫分離鎖可以有效地幫助減少鎖競爭,以提高系統(tǒng)性能。

比如線程A1,A2,A3進(jìn)行寫操作,B1,B2,B3進(jìn)行讀操作,如果市容重入鎖或者內(nèi)部鎖,則理論上所有讀之間、讀寫之間、寫寫之間都是串行操作。當(dāng)A1進(jìn)行讀取時,A2,A3則需要等待鎖。由于讀操作并不對數(shù)據(jù)的完整性造成破壞,這種等待顯然是不合理的。因此讀寫鎖就有發(fā)揮的余地。這種情況下,讀寫鎖允許多個線程同時讀,使得B1,B2,B3之間真正并行。但是考慮到數(shù)據(jù)完整性,寫寫操作和讀寫操作間依然需要互相等待和持有鎖。

如果在系統(tǒng)中,讀操作的次數(shù)遠(yuǎn)遠(yuǎn)大于寫操作,則讀寫鎖可以發(fā)揮最大的功效。

Condition對象


◆ ◆ ◆ ◆


線程間的協(xié)調(diào)工作光有鎖是不夠的,在業(yè)務(wù)層,可能會有復(fù)雜的線程間寫作的邏輯。Conditon對象就可以用于協(xié)調(diào)多線程的復(fù)雜協(xié)作。

Conditon是與鎖相關(guān)聯(lián)的。通過Lock接口的Conditon newConditon()方法可以生成一個與鎖綁定的Conditon實例。Conditon對象和鎖的關(guān)系,就如同Object.wait()、notify()兩個函數(shù)和synchronized關(guān)鍵字一樣,它們可以配合使用以完成對多線程的協(xié)調(diào)控制。

Semaphore信號量


◆ ◆ ◆ ◆


信號量為多線程寫作提供了更多強大的控制方法。廣義上說,信號量是對鎖的擴展。無論是內(nèi)部鎖synchronized還是重入鎖ReentrantLock,一次都只允許一個線程訪問一個資源,而信號量卻可以指定多個線程同時訪問某一個資源。

ThreadLocal線程局部變量


◆ ◆ ◆ ◆


ThreadLocal線程局部變量是一種多線程間并發(fā)訪問變量的解決方案。與synchronized等加鎖的方法不同,ThreadLocal完全不提供鎖,而使用以空間換時間的手段,為每個線程提供變量的獨立副本,以保證線程安全,因此它不是一種數(shù)據(jù)共享的解決方案。

從性能上看,ThreadLocal并不具有絕對的優(yōu)勢,在并發(fā)量不是很高時,也許加鎖的性能可能會更好。但是作為一套與鎖無關(guān)的線程安全按解決方案,在高并發(fā)量或者鎖競爭激烈的場合,使用ThreadLocal可以在一定程度上減少競爭。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多