国产成人精品亚洲777人妖,欧美日韩精品一区视频,最新亚洲国产,国产乱码精品一区二区亚洲

您的位置:首頁技術(shù)文章
文章詳情頁

詳解Java回環(huán)屏障CyclicBarrier

瀏覽:11日期:2022-08-25 08:18:34

上一篇說的CountDownLatch是一個計數(shù)器,類似線程的join方法,但是有一個缺陷,就是當計數(shù)器的值到達0之后,再調(diào)用CountDownLatch的await和countDown方法就會立刻返回,就沒有作用了,那么反正是一個計數(shù)器,為什么不能重復使用呢?于是就出現(xiàn)了這篇說的CyclicBarrier,它的狀態(tài)可以被重用;

一.簡單例子

用法其實和CountDownLatch差不多,也就是一個計數(shù)器,當計數(shù)器的值變?yōu)?之后,就會把阻塞的線程喚醒:

package com.example.demo.study;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Study0216 { // 注意這里的構(gòu)造器,第一個參數(shù)表示計數(shù)器初始值 // 第二個參數(shù)表示當計數(shù)器的值變?yōu)?的時候就觸發(fā)的任務(wù) static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> { System.out.println('cyclicBarrier task '); }); public static void main(String[] args) { // 新建兩個線程的線程池 ExecutorService pool = Executors.newFixedThreadPool(2); // 線程1放入線程池中 pool.submit(() -> { try { System.out.println('Thread1----await-begin'); cyclicBarrier.await(); System.out.println('Thread1----await-end'); } catch (Exception e) { e.printStackTrace(); } }); // 線程2放到線程池中 pool.submit(() -> { try { System.out.println('Thread2----await-begin'); cyclicBarrier.await(); System.out.println('Thread2----await-end'); } catch (Exception e) { e.printStackTrace(); } }); // 關(guān)閉線程池,此時還在執(zhí)行的任務(wù)會繼續(xù)執(zhí)行 pool.shutdown(); }}

詳解Java回環(huán)屏障CyclicBarrier

 我們再看看CyclicBarrier的復用性,這里比如有一個任務(wù),有三部分組成,分別是A,B,C,然后創(chuàng)建兩個線程去執(zhí)行這個任務(wù),必須要等到兩個線程都執(zhí)行完成A部分,然后才能開始執(zhí)行B,只有兩個線程都執(zhí)行完成B部分,才能執(zhí)行C:

package com.example.demo.study;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Study0216 { // 這里的構(gòu)造器,只有一個參數(shù),表示計數(shù)器初始值 static CyclicBarrier cyclicBarrier = new CyclicBarrier(2); public static void main(String[] args) { // 新建兩個線程的線程池 ExecutorService pool = Executors.newFixedThreadPool(2); // 線程1放入線程池中 pool.submit(() -> { try { System.out.println('Thread1----stepA-start'); cyclicBarrier.await();System.out.println('Thread1----stepB-start'); cyclicBarrier.await();System.out.println('Thread1----stepC-start'); } catch (Exception e) { e.printStackTrace(); } }); // 線程2放到線程池中 pool.submit(() -> { try { System.out.println('Thread2----stepA-start'); cyclicBarrier.await();System.out.println('Thread2----stepB-start'); cyclicBarrier.await();System.out.println('Thread2----stepC-start'); } catch (Exception e) { e.printStackTrace(); } }); // 關(guān)閉線程池,此時還在執(zhí)行的任務(wù)會繼續(xù)執(zhí)行 pool.shutdown(); }}

詳解Java回環(huán)屏障CyclicBarrier

二.基本原理

我們看看一些重要屬性:

public class CyclicBarrier { //這個內(nèi)部類只有一個boolean值 private static class Generation { boolean broken = false; } //獨占鎖 private final ReentrantLock lock = new ReentrantLock(); //條件變量 private final Condition trip = lock.newCondition(); //保存線程的總數(shù) private final int parties; //這是一個任務(wù),通過構(gòu)造器傳遞一個任務(wù),當計數(shù)器變?yōu)?之后,就可以執(zhí)行這個任務(wù) private final Runnable barrierCommand; //這類內(nèi)部之后一個boolean的值,表示屏障是否被打破 private Generation generation = new Generation(); //計數(shù)器 private int count;}

構(gòu)造器:

//我們的構(gòu)造器初始值設(shè)置的是partiespublic CyclicBarrier(int parties) { this(parties, null);}//注意,這里開始的時候是count等于parties//為什么要有兩個變量呢?我們每次調(diào)用await方法的時候count減一,當count的值變?yōu)?之后,怎么又還原成初始值呢?//直接就把parties的值賦值給count就行了呀,簡單吧!public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction;}

然后再看看await方法:

public int await() throws InterruptedException, BrokenBarrierException { try { //調(diào)用的是dowait方法 return dowait(false, 0L); } catch (TimeoutException toe) { throw new Error(toe); // cannot happen }}//假設(shè)count等于3,有三個線程都在調(diào)用這個方法,默認超時時間為0,那么首每次都只有一個線程可以獲取鎖,將count減一,不為0//就會到下面的for循環(huán)中扔到條件隊列中掛起;直到第三個線程調(diào)用這個dowait方法,count減一等于0,那么當前線程執(zhí)行任務(wù)之后,//就會喚醒條件變量中阻塞的線程,并重置count為初始值3private int dowait(boolean timed, long nanos)throws InterruptedException, BrokenBarrierException, TimeoutException { //獲取鎖 final ReentrantLock lock = this.lock; lock.lock(); try { //g中只有一個boolean值 final Generation g = generation; //如果g中的值為true的時候,拋錯 if (g.broken) throw new BrokenBarrierException(); //如果當前線程中斷,就拋錯 if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } //count減一,再賦值給index int index = --count; //如果index等于0的時候,說明所有的線程已經(jīng)到屏障點了,就可以 if (index == 0) { // tripped boolean ranAction = false; try { //執(zhí)行當前線程的任務(wù) final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true; //喚醒其他因為調(diào)用了await方法阻塞的線程 nextGeneration(); return 0; } finally { if (!ranAction) breakBarrier(); } } //能到這里來,說明是count不等于0,也就是還有的線程沒有到屏障點 for (;;) { try { //wait方法有兩種情況,一種是設(shè)置超時時間,一種是不設(shè)置超時時間 //這里就是對超時時間進行的一個判斷,如果設(shè)置的超時時間為0,則會在條件隊列中無限的等待下去,直到被喚醒 //設(shè)置了超時時間,那就等待該時間 if (!timed) trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { breakBarrier(); throw ie; } else { Thread.currentThread().interrupt(); } } if (g.broken) throw new BrokenBarrierException(); if (g != generation) return index; if (timed && nanos <= 0L) { breakBarrier(); throw new TimeoutException(); } } } finally { //釋放鎖 lock.unlock(); }}//喚醒其他因為調(diào)用了await方法阻塞的線程private void nextGeneration() { //喚醒條件變量中所有線程 trip.signalAll(); //重置count的值 count = parties; generation = new Generation();}private void breakBarrier() { generation.broken = true; //重置count為初始值parties count = parties; //喚醒條件隊列中的所有線程 trip.signalAll();}

以上就是詳解Java回環(huán)屏障CyclicBarrier的詳細內(nèi)容,更多關(guān)于Java CyclicBarrier的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標簽: Java
相關(guān)文章:
主站蜘蛛池模板: 柳林县| 宁波市| 盈江县| 南康市| 镶黄旗| 延川县| 大英县| 南溪县| 固阳县| 西乌珠穆沁旗| 惠安县| 泾源县| 汉阴县| 富平县| 富蕴县| 盘山县| 长汀县| 翼城县| 江达县| 南充市| 沁源县| 多伦县| 璧山县| 达拉特旗| 灵璧县| 三亚市| 方正县| 韩城市| 武清区| 昌平区| 桃江县| 巫溪县| 禄丰县| 莒南县| 华宁县| 安庆市| 利川市| 永安市| 新乐市| 剑阁县| 谢通门县|