一、CountDownLatch(減少計數)讓一些線程阻塞直到另一些線程完成一系列操作後才被喚醒
主要有兩個方法,
1.1 當一個或多個線程調用await方法時,這些線程會阻塞,其它線程調用countDown方法會將計數器減一(調用countDown方法的線程不會阻塞);
1.2 當計數器的值變爲0時,await方法阻塞的線程會被喚醒,繼續執行
示例代碼:
import java.util.concurrent.CountDownLatch;
/**
* 解釋:8個飯桶陸續離開食堂後掃地僧纔可以關燈
*
* main主線程必須要等前面8個線程完成全部工作後,自己才能開幹
*/
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
//8個在食堂的同學,各自離開食堂的時間不一致
for (int i = 1; i <= 8; i++){
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t 號飯桶離開食堂");
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "\t****** 掃地僧關燈走人");
}
}
二、CyclicBarrier(循環柵欄)可循環(Cyclic)使用的屏障(Barrier)
作用:讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,所有被屏障攔截的線程纔會繼續幹活,線程進入屏障通過CyclicBarrier的await()方法
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
*
* 集齊5福瓜分5億
*/
public class CyclicBarrierDemo {
private static final int NUMBER = 7;
public static void main(String[] args) {
//CyclicBarrier(int parties, Runnable barrierAction)
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("*****集齊5福瓜分5億");
});
for (int i = 1; i <= 5; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "\t 張福被收集 ");
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
三、Semaphore(信號量)用於多個共享資源的互斥使和控制併發線程數
3.1 acquire(獲取) 當一個線程調用acquire操作時,它要麼通過成功獲取信號量(信號量減1),要麼一直等下去,直到有線程釋放信號量,或超時;
3.2 release(釋放)實際上會將信號量的值加1,然後喚醒等待的線程。
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
*
* 廁所佔坑
*/
public class SemaphoreDemo {
public static void main(String[] args) {
//設置5個坑位
Semaphore semaphore = new Semaphore(5);
//設置9個人拉屎
for (int i = 1; i <= 9; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "\t 搶到了坑位");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName() + "\t------- 離開");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}