JUC的強大輔助類 juc中提供了常用的輔助類,通過這些輔助類,可以很好的解決線程數量過多時,Lock鎖的頻繁操作這三種輔助類為: 1.CountDownLatch,減少計數。 2.CyclicBarrier,迴圈柵欄。 3.Semaphore,信號燈。 減少計數器(CountDownLatch) ...
JUC的強大輔助類
juc中提供了常用的輔助類,通過這些輔助類,可以很好的解決線程數量過多時,Lock鎖的頻繁操作這三種輔助類為:
- 1.CountDownLatch,減少計數。
- 2.CyclicBarrier,迴圈柵欄。
- 3.Semaphore,信號燈。
減少計數器(CountDownLatch)
CountDownLatch類可以設置一個計數器,然後通過countDown方法來進行-1操作,使用await方法等待計數器的值<=0,然後繼續執行await方法之後的語句。
- 1.CountDownLatch,有兩個主要方法是await()和countDown(),當一個或多個線程調用await()時,這些線程會阻塞。
- 2.線程調用countDown()時,計數器的值會-1(調用countDown()方法不會阻塞)。
- 3.當計數器的值變為0時,因計數器.await(),阻塞的線程,會被喚醒繼續執行。
案例及代碼實現
/**
* @author 長名06
* @version 1.0
* 演示CountDownLatch
*/
public class CountDownLatchDemo {
//6位同學,陸續離開教室後,班長才鎖門
public static void main(String[] args) throws InterruptedException {
// 此代碼不能實現案例要求,因為mian線程和新增的線程間不是互斥狀態,並行執行,
// 很可能班長已經鎖門,但是還有同學未離開教室
// for (int i = 0; i < 6; i++) {
// new Thread(() ->{
// System.out.println(Thread.currentThread().getName() + "位同學離開教室");
// },String.valueOf(i + 1)).start();
// }
// System.out.println(Thread.currentThread().getName() + "班長鎖門了");
//第一步,創建計數器,定義初始值
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(() ->{
//需要執行的代碼,一定要寫在進行-1操作前,因為計數器的值一旦變為0,就會立刻喚醒,因其await()等待的線程,
//寫在之後的話,可能就會出現,主線程執行,其他線程才執行的情況
//第二步,執行線程需要的操作
System.out.println(Thread.currentThread().getName() + "位同學離開教室");
//第三步,進行-1操作
countDownLatch.countDown();//對設定的初始值,進行-1操作
},String.valueOf(i + 1)).start();
}
//第四步,使其他線程等待
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "班長鎖門了");
}
}
迴圈柵欄(CyclicBarrier)
CyclicBarrier是迴圈阻塞的意思,在使用中,Cyclic構造方法,第一個參數是目標數,每次執行CyclicBarrier一次,目標數會+1,只有達到了目標數,才會執行,傳入的第二個參數barrierAction 中的run方法。可以將CyclicBarrier.await()看作一次目標數+1並且阻塞當前線程的複合操作,且該阻塞方法,是在目標數達成後,統一喚醒因該方法阻塞的線程,繼續執行執行每個線程的操作。
案例及代碼實現
/**
* @author 長名06
* @version 1.0
* 演示迴圈柵欄CyclicBarrier
* 集齊七顆龍珠案例
*/
public class CyclicBarrierDemo {
//集齊七顆龍珠
private static final int NUMBER = 7;
public static void main(String[] args) {
//第一步,設定目標數,且指定目標數達成後,要執行的方法
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("七顆龍珠被集齊了");
});
for (int i = 1; i <= 7; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "星龍珠被收集到了");
//第二步+1,且阻塞線程
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() +"測試");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
信號燈(Semaphore)
Semaphore的構造方法,中傳入的第一個參數是最大信號量(可以看作線程池中的最大線程數),每個信號量初始化的數目,也就是能分發的最大許可證,使用acquire()方法,獲取許可證,release()方法釋放許可證。
案例及代碼實現
/**
* @author 長名06
* @version 1.0
* 信號燈 信號量
*/
public class SemaphoreDemo {
//實現6輛車,停入3個車位
public static void main(String[] args) {
Semaphore semaphore = new Semaphore( 3);
for (int i = 1; i < 7; i++) {
new Thread(() -> {
try {
// System.out.println(Thread.currentThread().getName() + "號車尋找車位中");
semaphore.acquire();//獲取信號量
System.out.println(Thread.currentThread().getName() + "號車,停車成功");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));//隨機等待幾秒
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName() + "號車,離開駛出車位");
semaphore.release();//釋放信號量操作
}
},String.valueOf(i)).start();
}
}
}
只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。