成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

【實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì)5】讓普通變量也享受原子操作

appetizerio / 2312人閱讀

摘要:有時(shí)候,由于初期考慮不周,或者后期的需求變化,一些普通變量可能也會(huì)有線程安全的需求。它可以讓你在不改動(dòng)或者極少改動(dòng)原有代碼的基礎(chǔ)上,讓普通的變量也享受操作帶來(lái)的線程安全性,這樣你可以修改極少的代碼,來(lái)獲得線程安全的保證。

有時(shí)候,由于初期考慮不周,或者后期的需求變化,一些普通變量可能也會(huì)有線程安全的需求。如果改動(dòng)不大,我們可以簡(jiǎn)單地修改程序中每一個(gè)使用或者讀取這個(gè)變量的地方。但顯然,這樣并不符合軟件設(shè)計(jì)中的一條重要原則——開(kāi)閉原則。也就是系統(tǒng)對(duì)功能的增加應(yīng)該是開(kāi)發(fā)的,而對(duì)修改應(yīng)該是相對(duì)保守的。而且,如果系統(tǒng)里使用到這個(gè)變量的地方特別多,一個(gè)一個(gè)修改也是一件令人厭煩的事情(況且很多使用場(chǎng)景下可能只是只讀的,并無(wú)線程安全的強(qiáng)烈要求,完全可以保持原樣)。

如果你有這種困擾,在這里根本不需要擔(dān)心,因?yàn)樵谠影镞€有一個(gè)實(shí)用的工具類(lèi)AtomicIntegerFieldUpdater。它可以讓你在不改動(dòng)(或者極少改動(dòng))原有代碼的基礎(chǔ)上,讓普通的變量也享受CAS操作帶來(lái)的線程安全性,這樣你可以修改極少的代碼,來(lái)獲得線程安全的保證。這聽(tīng)起來(lái)是不是讓人很激動(dòng)呢?

根據(jù)數(shù)據(jù)類(lèi)型不同,這個(gè)Updater有3種,分別是AtomicIntegerFieldUpdater、AtomicLongFieldUpdater和AtomicReferenceFieldUpdater。顧名思義,它們分別可以對(duì)int、long和普通對(duì)象就行CAS修改。

現(xiàn)在來(lái)思考這么一個(gè)場(chǎng)景。假設(shè)某地要進(jìn)行一次選舉?,F(xiàn)在模擬這個(gè)機(jī)票場(chǎng)景,如果選民投了候選人一票,就記為1,否則記為0。最終的選票顯然就是所有數(shù)據(jù)的簡(jiǎn)單求和。

01 public class AtomicIntegerFieldUpdaterDemo {
02     public static class Candidate{
03         int id;
04         volatile int score;
05     }
06     public final static AtomicIntegerFieldUpdater scoreUpdater 
07         = AtomicIntegerFieldUpdater.newUpdater(Candidate.class, "score");
08     //檢查Updater是否工作正確
09     public static AtomicInteger allScore=new AtomicInteger(0);
10     public static void main(String[] args) throws InterruptedException {
11         final Candidate stu=new Candidate();
12         Thread[] t=new Thread[10000];
13         for(int i = 0 ; i < 10000 ; i++) {  
14             t[i]=new Thread() {  
15                 public void run() {  
16                     if(Math.random()>0.4){
17                         scoreUpdater.incrementAndGet(stu);
18                         allScore.incrementAndGet();
19                     }
20                 }  
21             };
22             t[i].start();
23         }  
24         for(int i = 0 ; i < 10000 ; i++) {  t[i].join();}
25         System.out.println("score="+stu.score);
26         System.out.println("allScore="+allScore);
27     }
28 }
 

上述代碼模擬了這個(gè)計(jì)票場(chǎng)景。候選人的得票數(shù)量記錄在Candidate.score中。注意,它是一個(gè)普通的volatile變量。而volatile變量并不是線程安全的。第6~7行定義了

AtomicIntegerFieldUpdater實(shí)例,用來(lái)對(duì)Candidate.score進(jìn)行寫(xiě)入。而后續(xù)的allScore我們用來(lái)檢查AtomicIntegerFieldUpdater的正確性。如果AtomicIntegerFieldUpdater真的保證了線程安全,那么最終Candidate.score和allScore的值必然是相等的。否則,就說(shuō)明AtomicIntegerFieldUpdater根本沒(méi)有確保線程安全的寫(xiě)入。第12~21行模擬了計(jì)票過(guò)程,這里假設(shè)有大約60%的人投贊成票,并且投票是隨機(jī)進(jìn)行的。第17行使用Updater修改Candidate.score(這里應(yīng)該是線程安全的),第18行使用AtomicInteger計(jì)數(shù),作為參考基準(zhǔn)。

大家如果運(yùn)行這段程序,不難發(fā)現(xiàn),最終的Candidate.score總是和allScore絕對(duì)相等。這說(shuō)明AtomicIntegerFieldUpdater很好地保證了Candidate.score的線程安全。

雖然AtomicIntegerFieldUpdater很好用,但是還是有幾個(gè)注意事項(xiàng):

第一,Updater只能修改它可見(jiàn)范圍內(nèi)的變量。因?yàn)閁pdater使用反射得到這個(gè)變量。如果變量不可見(jiàn),就會(huì)出錯(cuò)。比如如果score申明為private,就是不可行的。

第二,為了確保變量被正確的讀取,它必須是volatile類(lèi)型的。如果我們?cè)写a中未申明這個(gè)類(lèi)型,那么簡(jiǎn)單得申明一下就行,這不會(huì)引起什么問(wèn)題。

第三,由于CAS操作會(huì)通過(guò)對(duì)象實(shí)例中的偏移量直接進(jìn)行賦值,因此,它不支持static字段(Unsafe. objectFieldOffset()不支持靜態(tài)變量)。

好了,通過(guò)AtomicIntegerFieldUpdater,是不是讓我們可以更加隨心所欲得對(duì)系統(tǒng)關(guān)鍵數(shù)據(jù)進(jìn)行線程安全地保護(hù)呢?

【實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì)1】Java中的指針:Unsafe類(lèi)
【實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì)2】無(wú)鎖的對(duì)象引用:AtomicReference
【實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì) 3】帶有時(shí)間戳的對(duì)象引用:AtomicStampedReference
【實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì) 4】數(shù)組也能無(wú)鎖AtomicIntegerArray

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65622.html

相關(guān)文章

  • 實(shí)戰(zhàn)Java并發(fā)程序設(shè)計(jì)6】挑戰(zhàn)無(wú)鎖算法

    摘要:在本例中,講述的無(wú)鎖來(lái)自于并發(fā)包我們將這個(gè)無(wú)鎖的稱(chēng)為。在這里,我們使用二維數(shù)組來(lái)表示的內(nèi)部存儲(chǔ),如下變量存放所有的內(nèi)部元素。為什么使用二維數(shù)組去實(shí)現(xiàn)一個(gè)一維的呢這是為了將來(lái)進(jìn)行動(dòng)態(tài)擴(kuò)展時(shí)可以更加方便。 我們已經(jīng)比較完整得介紹了有關(guān)無(wú)鎖的概念和使用方法。相對(duì)于有鎖的方法,使用無(wú)鎖的方式編程更加考驗(yàn)一個(gè)程序員的耐心和智力。但是,無(wú)鎖帶來(lái)的好處也是顯而易見(jiàn)的,第一,在高并發(fā)的情況下,它比有鎖...

    zengdongbao 評(píng)論0 收藏0
  • 并發(fā) - 基礎(chǔ)

    摘要:異步非阻塞方式,任務(wù)的完成的通知由其他線程發(fā)出。并發(fā)并行死鎖饑餓活鎖死鎖線程持有,線程持有。如等,在多線程情況下,該操作不是原子級(jí)別的而是原子的,所以一般用于狀態(tài)標(biāo)記。 同步/異步、阻塞/非阻塞 同步/異步是 API 被調(diào)用者的通知方式。阻塞/非阻塞則是 API 調(diào)用者的等待方式(線程掛機(jī)/不掛起)。 同步非阻塞 Future方式,任務(wù)的完成要主線程自己判斷。如NIO,后臺(tái)有多個(gè)任務(wù)在...

    phpmatt 評(píng)論0 收藏0
  • java-實(shí)戰(zhàn)java并發(fā)程序設(shè)計(jì)-ch1走入并行的世界

    摘要:參考何去何從的并行計(jì)算忘記該死的并行并行程序的復(fù)雜性和亂序性,并行程序設(shè)計(jì)十分復(fù)雜。可怕的現(xiàn)實(shí)摩爾定律的失效單核上的晶體管數(shù)目達(dá)到極限。并發(fā)級(jí)別阻塞重入鎖無(wú)饑餓兩個(gè)線程優(yōu)先級(jí)不同,低優(yōu)先級(jí)的可能產(chǎn)生饑餓。 Chapter1 參考:https://github.com/chengbingh... 1.1何去何從的并行計(jì)算 1.1.1 忘記該死的并行并行程序的復(fù)雜性和亂序性,并行程序設(shè)計(jì)十...

    suxier 評(píng)論0 收藏0
  • 實(shí)戰(zhàn)java并發(fā)程序設(shè)計(jì)第一章

    摘要:通過(guò)指令重排可以減少流水線停頓提升巨大效率原則程序順序原則一個(gè)線程內(nèi)保證語(yǔ)義的串行性。鎖規(guī)則解鎖必然發(fā)生在隨后的加鎖前。線程的方法先于它的每一個(gè)動(dòng)作。 1. 基本概念 同步(Synchronous)和異步(Asynchronous) 并發(fā)(Conncurrency)和并行(Parallelism) 臨界區(qū) 阻塞(Blocking)與非阻塞(Non-Blocking) 死鎖(Deadl...

    moven_j 評(píng)論0 收藏0
  • 實(shí)戰(zhàn)Java并發(fā)程序設(shè)計(jì) 4】數(shù)組能無(wú)鎖AtomicIntegerArray

    摘要:當(dāng)前可用的原子數(shù)組有和,分別表示整數(shù)數(shù)組型數(shù)組和普通的對(duì)象數(shù)組。摘自實(shí)戰(zhàn)高并發(fā)程序設(shè)計(jì)一書(shū)實(shí)戰(zhàn)高并發(fā)程序設(shè)計(jì)中的指針類(lèi)實(shí)戰(zhàn)高并發(fā)程序設(shè)計(jì)無(wú)鎖的對(duì)象引用實(shí)戰(zhàn)高并發(fā)程序設(shè)計(jì)帶有時(shí)間戳的對(duì)象引用 除了提供基本數(shù)據(jù)類(lèi)型外,JDK還為我們準(zhǔn)備了數(shù)組等復(fù)合結(jié)構(gòu)。當(dāng)前可用的原子數(shù)組有:AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray,分別...

    zlyBear 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<