Java wait和notifyAll實現(xiàn)簡單的阻塞隊列
wait,會使調(diào)用的線程進(jìn)入等待狀態(tài),會釋放所持有的對象鎖(調(diào)用的時候也必須先獲取到鎖,否則會拋出異常 IllegalMonitorStateException)
notifyAll、notify,會去喚醒應(yīng)當(dāng)前對象而等待的線程,(調(diào)用的時候也必須先獲取到鎖,否則會拋出異常 IllegalMonitorStateException)
順便也記錄一下join方法,調(diào)用join方法,會使當(dāng)前線程進(jìn)入等待,如果沒有設(shè)置等待時間,就會等待另一個線程執(zhí)行完成才返回(ps:調(diào)用join方法并不一定立刻執(zhí)行另一個線程,只是當(dāng)前線程進(jìn)入等待,然后切換下一個線程)
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author lhd
*/
public class BlockQueue {
/**
* 生產(chǎn)者鎖對象
*/
private final Object addLock = new Object();
/**
* 消費者鎖對象
*/
private final Object deleteLock = new Object();
/**
* 隊列總大小
*/
private final Integer size = 30;
/**
* 數(shù)據(jù)存放
*/
private Object[] queue = new Object[size];
/**
* 存放的數(shù)量,使用AtomicInteger是因為普通的int遞增遞減操作會存在非原子性的問題,會使數(shù)量異常
*/
private AtomicInteger count = new AtomicInteger(0);
/**
* 生產(chǎn)
* @param o 對象
*/
public void add(Object o) {
//獲取生產(chǎn)鎖,wait方法必須獲取到對象鎖后才可以調(diào)用,否則拋出異常
synchronized (addLock){
//判斷是否超過隊列大小,超過則進(jìn)入等待
while (count.get() >= size){
try {
addLock.wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
//存放一個
queue[count.get()] = o;
//遞增
int i = count.incrementAndGet();
//打印一下日志
String name = Thread.currentThread().getName();
System.out.println(name + "生產(chǎn)了一個,現(xiàn)有數(shù)量" + i);
}
//如果隊列有數(shù)據(jù),則調(diào)用notifyAll喚醒消費者
if (count.get() >= 1){
//notifyAll、notify都需要先獲取對象鎖,否則會拋出異常
synchronized (deleteLock){
deleteLock.notifyAll();
}
}
}
/**
* 消費
* @return
*/
public Object poll(){
Object o;
//先獲取對象鎖,和生產(chǎn)者類似
synchronized (deleteLock){
//隊列里沒有數(shù)據(jù)則等待
while (count.get() <= 0){
try {
deleteLock.wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
//獲取數(shù)據(jù)
o = queue[count.get()];
//遞減
int i = count.decrementAndGet();
String name = Thread.currentThread().getName();
System.out.println(name + "消費了一個,現(xiàn)有數(shù)量" + i);
}
//如果隊列沒有滿,則可以喚醒生產(chǎn)者
if (count.get() < size){
//需要先獲取到鎖
synchronized (addLock){
addLock.notifyAll();
}
}
return o;
}
/**
* 簡單的測試
* @param args
*/
public static void main(String[] args) {
BlockQueue blockQueue = new BlockQueue();
Thread t1 = new Thread(()-> {
while (true){
blockQueue.add(new Object());
}
}
);
Thread t2 = new Thread(()-> {
while (true){
blockQueue.add(new Object());
}
}
);
Thread t3 = new Thread(()-> {
while (true){
blockQueue.add(new Object());
}
}
);
Thread t4 = new Thread(()-> {
while (true){
blockQueue.poll();
}
}
);
Thread t5 = new Thread(()-> {
while (true){
blockQueue.poll();
}
}
);
Thread t6 = new Thread(()-> {
while (true){
blockQueue.poll();
}
}
);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
效果:其實這個遞增遞減操作和打印操作也不是原子操作

依次打印線程1,2,3
/**
* @author lhd
*/
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> System.out.println(1));
Thread t2 = new Thread(()-> System.out.println(2));
Thread t3 = new Thread(()-> System.out.println(3));
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringMVC中@RequestMapping注解用法實例
通過@RequestMapping注解可以定義不同的處理器映射規(guī)則,下面這篇文章主要給大家介紹了關(guān)于SpringMVC中@RequestMapping注解用法的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
Java數(shù)據(jù)結(jié)構(gòu)之隊列與OJ題
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之隊列與OJ題,本文章先是對隊列進(jìn)行介紹,后又介紹了四道OJ相關(guān)的題目,來使其深入理解,需要的朋友可以參考下2023-01-01
Spring Cloud Ribbon負(fù)載均衡器處理方法
這篇文章主要介紹了Spring Cloud Ribbon負(fù)載均衡器處理方法,看看是如何獲取服務(wù)實例,獲取以后做了哪些處理,處理后又是如何選取服務(wù)實例的,需要的朋友可以參考下2018-02-02
SpringCloud客戶端報錯:- was unable to send&nb
這篇文章主要介紹了SpringCloud客戶端報錯:- was unable to send heartbeat!的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05
在JPA中criteriabuilder使用or拼接多個like語句
這篇文章主要介紹了在JPA中criteriabuilder使用or拼接多個like語句,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

