JUC三大輔助類
一、CountDownLatch:減少計數方法
作用:讓一些線程阻塞直到另一些線程完成一系列操作後才被喚醒。
提供的三個方法:
new CountDownLatch(6);
設置計數器爲6個線程countDown();
將計數器減1(調用countDown方法的線程不會阻塞)await();
計數器的值>0,線程會阻塞,當計數器的值=0時,因await()方法阻塞的線程會被喚醒,繼續執行
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo
{
public static void main(String[] args) throws InterruptedException
{
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <=6; i++) //6個上自習的同學,各自離開教室的時間不一致
{
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"\t 號同學離開教室");
//線程調用countDown()方法會將計數器減1(調用countDown方法的線程不會阻塞)
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
//線程調用await()方法時,這些線程會阻塞
countDownLatch.await();
//當計數器的值變爲0時,因await()方法阻塞的線程會被喚醒,繼續執行
System.out.println(Thread.currentThread().getName()+"\t****** 班長關門走人,main線程是班長");
}
}
二、CyclicBarrier:循環柵欄方法
作用:讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,所有被屏障攔截的線程纔會繼續執行。
提供的方法:
new CyclicBarrier(int parties, Runnable barrierAction);
構造方法中:需要類實現Runnable接口cyclicBarrier.await();
同步點阻塞
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
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("*****集齊7顆龍珠就可以召喚神龍");}) ;
for (int i = 1; i <= 7; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName()+"\t 星龍珠被收集 ");
//阻塞點 awaitCurrent >= 7 ? openAwait() : await();
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
三、Semaphore:信號燈
作用:
- 用於多個共享資源的互斥使用
- 用於併發線程數的控制。
提供的方法:
new Semaphore(3);
//模擬3個資源,可申請使用可釋放acquire();
申請,當一個線程調用acquire()操作時,它要麼通過,成功獲取信號量(信號量減1),要麼一直等下去,直到有線程釋放信號量,或超時release();
釋放,使用在finally{}中,會將信號量的值加1,然後喚醒等待的線程
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo
{
public static void main(String[] args)
{
Semaphore semaphore = new Semaphore(3);//模擬3個停車位
for (int i = 1; i <=6; i++) //模擬6部汽車
{
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();
}
}
}
ReadWriteLock:讀寫鎖
- import java.util.concurrent.locks.*;三種鎖:
- Condition
- Lock
- ReadWriteLock
作用:多線程同時讀寫數據時會出現混亂,用讀寫鎖將讀寫分開,讓寫分離,讀讀共享
提供方法:
ReadWriteLock rwLock = new ReentrantReadWriteLock();
實現類構造器- 寫鎖writeLock:
rwLock.writeLock().lock();
,在finally{}處解鎖:rwLock.writeLock().unlock();
- 讀鎖readLock:
rwLock.readLock().lock();
,在finally{}處解鎖:rwLock.readLock().unlock();
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
private ReadWriteLock rwLock = new ReentrantReadWriteLock();
public void put(String key, Object value) {
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t 正在寫" + key);
//暫停一會兒線程
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t 寫完了" + key);
System.out.println();
} catch (Exception e) {
e.printStackTrace();
} finally {
rwLock.writeLock().unlock();
}
}
public Object get(String key) {
rwLock.readLock().lock();
Object result = null;
try {
System.out.println(Thread.currentThread().getName() + "\t 正在讀" + key);
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
result = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t 讀完了" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
rwLock.readLock().unlock();
}
return result;
}
}
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 1; i <= 5; i++) {
final int num = i;
new Thread(() -> {
myCache.put(num + "", num + "");
}, String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) {
final int num = i;
new Thread(() -> {
myCache.get(num + "");
}, String.valueOf(i)).start();
}
}
}
BlockingQueue:阻塞隊列
當隊列是空的,從隊列中獲取元素的操作將會被阻塞
當隊列是滿的,從隊列中添加元素的操作將會被阻塞
-
Collection
- Queue
- BlockingQueue:阻塞隊列
- ArrayBlockingQueue:數組結構阻塞隊列
- LinkedBlockingQueue:鏈表結構阻塞隊列(大小默認值爲Integer.MAX_VALUE)
- SynchronousQueue:單元素阻塞隊列
- PriorityBlockingQueue:優先級排序無界阻塞隊列
- DelayQueue:優先級延遲無界阻塞隊列
- LinkedTransferQueue:鏈表無界阻塞隊列
- LinkedBlockingDeque:鏈表雙向阻塞隊列
- BlockingQueue:阻塞隊列
- Queue
-
BlockingQueue的方法:
- 創建方法:
BlockingQueue<String> Queue = new ArrayBlockingQueue<>(int initSize);
- 創建方法:
方法類型 | 拋出異常 | 返回特殊值 | 阻塞 | 超時 |
---|---|---|---|---|
插入 | boolean add(e) | boolean offer(e) | void put(e) | boolean offer(e,timeout,timeunit) |
刪除 | E remove() | E poll() | E take() | boolean poll(e,timeout,timeunit) |
檢查 | E element() | E peek() | / | / |
類型 | 說明 |
---|---|
拋出異常 | 1. 當阻塞隊列滿時,再往隊列裏add插入元素 會拋IllegalStateException:Queue full 2. 當阻塞隊列空時,再往隊列裏remove移除元素 會拋NoSuchElementException |
特殊值 | 1. 插入方法,成功ture失敗false 2. 刪除方法,成功返回出隊列的元素,隊列裏沒有就返回null |
一直阻塞 | 1. 當阻塞隊列滿時,生產者線程繼續往隊列裏put元素, 隊列會一直阻塞生產者線程直到put數據or響應中斷退出 2. 當阻塞隊列空時,消費者線程試圖從隊列裏take元素, 隊列會一直阻塞消費者線程直到隊列可用 |
超時退出 | 當阻塞隊列滿時,隊列會阻塞生產者線程一定時間,超過限時後生產者線程會退出 |