国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

《Java并發(fā)編程實(shí)戰(zhàn)》課程筆記(十二)

這篇具有很好參考價(jià)值的文章主要介紹了《Java并發(fā)編程實(shí)戰(zhàn)》課程筆記(十二)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

CountDownLatch 和 CyclicBarrier:如何讓多線程步調(diào)一致?

原始對(duì)賬系統(tǒng)

  • 對(duì)賬系統(tǒng)的業(yè)務(wù)簡(jiǎn)化后:
    • 首先用戶通過(guò)在線商城下單,會(huì)生成電子訂單,保存在訂單庫(kù);
    • 之后物流會(huì)生成派送單給用戶發(fā)貨,派送單保存在派送單庫(kù)。
    • 為了防止漏派送或者重復(fù)派送,對(duì)賬系統(tǒng)每天還會(huì)校驗(yàn)是否存在異常訂單。
  • 目前對(duì)賬系統(tǒng)的處理邏輯是首先查詢訂單,然后查詢派送單,之后對(duì)比訂單和派送單,將差異寫入差異庫(kù)。
    《Java并發(fā)編程實(shí)戰(zhàn)》課程筆記(十二)
  • 對(duì)賬系統(tǒng)的核心代碼如下,就是在一個(gè)單線程里面循環(huán)查詢訂單、派送單,然后執(zhí)行對(duì)賬,最后將寫入差異庫(kù)。
    while (存在未對(duì)賬訂單) {
    	// 查詢未對(duì)賬訂單
    	pos = getPOrders();
    	// 查詢派送單
    	dos = getDOrders();
    	// 執(zhí)?對(duì)賬操作
    	diff = check(pos, dos);
    	// 差異寫?差異庫(kù)
    	save(diff);
    }
    

利用并行優(yōu)化對(duì)賬系統(tǒng)

  • 對(duì)于串行化的系統(tǒng),優(yōu)化性能首先想到的是能否利用多線程并行處理。
    • 查詢未對(duì)賬訂單 getPOrders() 和查詢派送單 getDOrders() 是否可以并行處理呢?
    • 顯然是可以的,因?yàn)檫@兩個(gè)操作并沒(méi)有先后順序的依賴。
      while () {
      	// 查詢未對(duì)賬訂單
      	Thread t1 = new Thread(() -> {
      		pos = getPOrders();
      	});
      	t1.start();
      	// 查詢派送單
      	Thread t2 = new Thread(()->{
      		dos = getDOrders();
      	});
      	t2.start();
      	// 等待 t1、t2 結(jié)束
      	t1.join();
      	t2.join();
      	// 執(zhí)?對(duì)賬操作
      	diff = check(pos, dos);
      	// 差異寫?差異庫(kù)
      	save(diff);
      }
      

用 CountDownLatch 實(shí)現(xiàn)線程等待

  • while 循環(huán)里面每次都會(huì)創(chuàng)建新的線程,而創(chuàng)建線程可是個(gè)耗時(shí)的操作。所以最好是創(chuàng)建出來(lái)的線程能夠循環(huán)利用,線程池就能解決這個(gè)問(wèn)題。
    Executor executor = Executors.newFixedThreadPool(2);
    while (存在未對(duì)賬訂單) {
    	// 計(jì)數(shù)器初始化為 2
    	CountDownLatch latch = new CountDownLatch(2);
    	// 查詢未對(duì)賬訂單
    	executor.execute(() -> {
    		pos = getPOrders();
    		latch.countDown();
    	});
    	// 查詢派送單
    	executor.execute(()-> {
    		dos = getDOrders();
    		latch.countDown();
        });
    	// 等待兩個(gè)查詢操作結(jié)束
    	latch.await();
    	// 執(zhí)?對(duì)賬操作
    	diff = check(pos, dos);
    	// 差異寫?差異庫(kù)
    	save(diff);
    }
    
  • 我們將 getPOrders() 和 getDOrders() 這兩個(gè)查詢操作并行了,但這兩個(gè)查詢操作和對(duì)賬操作 check()、save() 之間還是串行的。很顯然,這兩個(gè)查詢操作和對(duì)賬操作也是可以并行的,也就是說(shuō),在執(zhí)行對(duì)賬操作的時(shí)候,可以同時(shí)去執(zhí)行下一輪的查詢操作。
    • 針對(duì)對(duì)賬這個(gè)項(xiàng)目,我設(shè)計(jì)了兩個(gè)隊(duì)列,并且兩個(gè)隊(duì)列的元素之間還有對(duì)應(yīng)關(guān)系。
    • 訂單查詢操作將訂單查詢結(jié)果插入訂單隊(duì)列,派送單查詢操作將派送單插入派送單隊(duì)列,這兩個(gè)隊(duì)列的元素之間是有對(duì)應(yīng)關(guān)系的。
    • 兩個(gè)隊(duì)列的好處是,對(duì)賬操作可以每次從訂單隊(duì)列出一個(gè)元素,從派送單隊(duì)列出一個(gè)元素,然后對(duì)這兩個(gè)元素執(zhí)行對(duì)賬操作,這樣數(shù)據(jù)一定不會(huì)亂掉。
      《Java并發(fā)編程實(shí)戰(zhàn)》課程筆記(十二)
    • ?個(gè)線程 T1 執(zhí)行訂單的查詢工作,一個(gè)線程 T2 執(zhí)行派送單的查詢工作,當(dāng)線程 T1 和 T2 都各自生產(chǎn)完 1 條數(shù)據(jù)的時(shí)候,通知線程 T3 執(zhí)行對(duì)賬操作。
    • 線程 T1 和線程 T2 只有都生產(chǎn)完 1 條數(shù)據(jù)的時(shí)候,才能一起向下執(zhí)行,也就是說(shuō),線程 T1 和線程 T2 要互相等待,步調(diào)要一致。
    • 同時(shí)當(dāng)線程 T1和 T2 都生產(chǎn)完一條數(shù)據(jù)的時(shí)候,還要能夠通知線程 T3 執(zhí)行對(duì)賬操作。

用 CyclicBarrier 實(shí)現(xiàn)線程同步

  • 我們首先創(chuàng)建了一個(gè)計(jì)數(shù)器初始值為 2 的 CyclicBarrier,你需要注意的是創(chuàng)建 CyclicBarrier 的時(shí)候,我們還傳入了一個(gè)回調(diào)函數(shù),當(dāng)計(jì)數(shù)器減到 0 的時(shí)候,會(huì)調(diào)用這個(gè)回調(diào)函數(shù)。
    • 線程 T1 負(fù)責(zé)查詢訂單,當(dāng)查出一條時(shí),調(diào)用 barrier.await() 來(lái)將計(jì)數(shù)器減 1,同時(shí)等待計(jì)數(shù)器變成 0;
    • 線程 T2 負(fù)責(zé)查詢派送單,當(dāng)查出一條時(shí),也調(diào)用 barrier.await() 來(lái)將計(jì)數(shù)器減 1,同時(shí)等待計(jì)數(shù)器變成 0;
    • 當(dāng) T1 和 T2 都調(diào)用 barrier.await() 的時(shí)候,計(jì)數(shù)器會(huì)減到 0,此時(shí) T1 和 T2 就可以執(zhí)行下?條語(yǔ)句了,同時(shí)會(huì)調(diào)用 barrier 的回調(diào)函數(shù)來(lái)執(zhí)行對(duì)賬操作。
    • CyclicBarrier 的計(jì)數(shù)器有自動(dòng)重置的功能,當(dāng)減到 0 的時(shí)候,會(huì)自動(dòng)重置你設(shè)置的初始值。
      // 訂單隊(duì)列
      Vector<P> pos;
      // 派送單隊(duì)列
      Vector<D> pos;
      // 執(zhí)?回調(diào)的線程池
      Executor executor = Executors.newFixedThreadPool(1);
      final CyclicBarrier barrier = new CyclicBarrier(2, () -> { executor.execute(() -> check()); });
      
      void check() {
      	P p = pos.remove(0);
      	D d = dos.remove(0);
      	// 執(zhí)?對(duì)賬操作
      	diff = check(p, d);
      	// 差異寫?差異庫(kù)
      	save(diff);
      }
      
      void checkAll() {
      	// 循環(huán)查詢訂單庫(kù)
      	Thread t1 = new Thread(() -> {
      		while (存在未對(duì)賬訂單) {
      			// 查詢訂單庫(kù)
      			pos.add(getPOrders());
      			// 等待
      			barrier.await();
      		}
      	});
      	t1.start();
      	// 循環(huán)查詢運(yùn)單庫(kù)
      	Thread T2 = new Thread(()->{
      		while(存在未對(duì)賬訂單){
      			// 查詢運(yùn)單庫(kù)
      			dos.add(getDOrders());
      			// 等待
      			barrier.await();
      			}
      	});
      	T2.start();
      }
      

文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-476429.html

到了這里,關(guān)于《Java并發(fā)編程實(shí)戰(zhàn)》課程筆記(十二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 5.5. Java并發(fā)工具類(如CountDownLatch、CyclicBarrier等)

    5.5. Java并發(fā)工具類(如CountDownLatch、CyclicBarrier等)

    5.5.1 CountDownLatch CountDownLatch 是一個(gè)同步輔助類,它允許一個(gè)或多個(gè)線程等待,直到其他線程完成一組操作。 CountDownLatch 有一個(gè)計(jì)數(shù)器,當(dāng)計(jì)數(shù)器減為0時(shí),等待的線程將被喚醒。計(jì)數(shù)器只能減少,不能增加。 示例:使用CountDownLatch等待所有線程完成任務(wù) 假設(shè)我們有一個(gè)任務(wù)需

    2024年02月07日
    瀏覽(23)
  • 《C++并發(fā)編程實(shí)戰(zhàn)》讀書(shū)筆記(3):并發(fā)操作的同步

    當(dāng)線程需要等待特定事件發(fā)生、或是某個(gè)條件成立時(shí),可以使用條件變量 std::condition_variable ,它在標(biāo)準(zhǔn)庫(kù)頭文件 condition_variable 內(nèi)聲明。 wait() 會(huì)先在內(nèi)部調(diào)用lambda函數(shù)判斷條件是否成立,若條件成立則 wait() 返回,否則解鎖互斥并讓當(dāng)前線程進(jìn)入等待狀態(tài)。當(dāng)其它線程調(diào)用

    2024年02月10日
    瀏覽(22)
  • 《C++并發(fā)編程實(shí)戰(zhàn)》讀書(shū)筆記(4):原子變量

    標(biāo)準(zhǔn)原子類型的定義位于頭文件 atomic 內(nèi)。原子操作的關(guān)鍵用途是取代需要互斥的同步方式,但假設(shè)原子操作本身也在內(nèi)部使用了互斥,就很可能無(wú)法達(dá)到期望的性能提升。有三種方法來(lái)判斷一個(gè)原子類型是否屬于無(wú)鎖數(shù)據(jù)結(jié)構(gòu): 所有標(biāo)準(zhǔn)原子類型( std::atomic_flag 除外,因?yàn)?/p>

    2024年02月10日
    瀏覽(28)
  • 《C++并發(fā)編程實(shí)戰(zhàn)》讀書(shū)筆記(1):線程管控

    包含頭文件 thread 后,通過(guò)構(gòu)建 std::thread 對(duì)象啟動(dòng)線程,任何可調(diào)用類型都適用于 std::thread 。 啟動(dòng)線程后,需要明確是等待它結(jié)束、還是任由它獨(dú)自運(yùn)行: 調(diào)用成員函數(shù) join() 會(huì)先等待線程結(jié)束,然后隸屬于該線程的任何存儲(chǔ)空間都會(huì)被清除, std::thread 對(duì)象不再關(guān)聯(lián)到已結(jié)

    2024年02月10日
    瀏覽(20)
  • Java并發(fā)編程實(shí)戰(zhàn)

    2023年06月19日
    瀏覽(20)
  • 《C++并發(fā)編程實(shí)戰(zhàn)》讀書(shū)筆記(2):線程間共享數(shù)據(jù)

    在C++中,我們通過(guò)構(gòu)造 std::mutex 的實(shí)例來(lái)創(chuàng)建互斥量,調(diào)用成員函數(shù) lock() 對(duì)其加鎖,調(diào)用 unlock() 解鎖。但通常更推薦的做法是使用標(biāo)準(zhǔn)庫(kù)提供的類模板 std::lock_guard ,它針對(duì)互斥量實(shí)現(xiàn)了RAII手法:在構(gòu)造時(shí)給互斥量加鎖,析構(gòu)時(shí)解鎖。兩個(gè)類都在頭文件 mutex 里聲明。 假設(shè)

    2024年02月10日
    瀏覽(11)
  • python:并發(fā)編程(十二)

    本文將和大家一起探討python的多協(xié)程并發(fā)編程 (下篇) ,使用內(nèi)置基本庫(kù)asyncio來(lái)實(shí)現(xiàn)并發(fā),先通過(guò)官方來(lái)簡(jiǎn)單使用這個(gè)模塊。先打好基礎(chǔ),能夠有個(gè)基本的用法與認(rèn)知,后續(xù)文章,我們?cè)龠M(jìn)行詳細(xì)使用。 本文為python并發(fā)編程的第十二篇,上一篇文章地址如下: python:并發(fā)

    2024年02月09日
    瀏覽(19)
  • java并發(fā)編程之美第五章讀書(shū)筆記

    java并發(fā)編程之美第五章讀書(shū)筆記

    CopyOnWriteArrayList 線程安全的ArrayList,對(duì)其進(jìn)行的修改操作都是在底層的一個(gè)復(fù)制的數(shù)組(快照)進(jìn)行的,也就是寫時(shí)復(fù)制策略 類圖 每一個(gè)對(duì)象里面有一個(gè)array數(shù)組進(jìn)行存放具體的元素,ReentrantLock獨(dú)占鎖對(duì)象用來(lái)保證同時(shí)只有一個(gè)線程對(duì)array進(jìn)行修改,這里只要記得ReentrantLock是獨(dú)占鎖

    2024年02月03日
    瀏覽(21)
  • Java并發(fā)編程學(xué)習(xí)筆記(一)線程的入門與創(chuàng)建

    Java并發(fā)編程學(xué)習(xí)筆記(一)線程的入門與創(chuàng)建

    認(rèn)識(shí) 程序由指令和數(shù)據(jù)組成,簡(jiǎn)單來(lái)說(shuō),進(jìn)程可以視為程序的一個(gè)實(shí)例 大部分程序可以同時(shí)運(yùn)行多個(gè)實(shí)例進(jìn)程,例如記事本、畫(huà)圖、瀏覽器等 少部分程序只能同時(shí)運(yùn)行一個(gè)實(shí)例進(jìn)程,例如QQ音樂(lè)、網(wǎng)易云音樂(lè)等 一個(gè)進(jìn)程可以分為多個(gè)線程,線程為最小調(diào)度單位,進(jìn)程則是作

    2024年02月16日
    瀏覽(48)
  • 【項(xiàng)目實(shí)戰(zhàn)】并發(fā)編程之Java中使用五種方式實(shí)現(xiàn)延時(shí)執(zhí)行調(diào)用

    To實(shí)現(xiàn)延時(shí)執(zhí)行調(diào)用,Java中可以使用Thread.sleep()方法。該方法接受一個(gè)以毫秒為單位的時(shí)間參數(shù),使當(dāng)前線程休眠指定的時(shí)間。在休眠期間,線程不會(huì)執(zhí)行任何操作。 以下是一個(gè)示例代碼塊,演示如何使用Thread.sleep()方法實(shí)現(xiàn)延時(shí)執(zhí)行調(diào)用:

    2024年02月15日
    瀏覽(19)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包