Java wait和notifyAll實現簡單的阻塞佇列
阿新 • • 發佈:2020-01-07
wait,會使呼叫的執行緒進入等待狀態,會釋放所持有的物件鎖(呼叫的時候也必須先獲取到鎖,否則會丟擲異常 IllegalMonitorStateException)
notifyAll、notify,會去喚醒應當前物件而等待的執行緒,(呼叫的時候也必須先獲取到鎖,否則會丟擲異常 IllegalMonitorStateException)
順便也記錄一下join方法,呼叫join方法,會使當前執行緒進入等待,如果沒有設定等待時間,就會等待另一個執行緒執行完成才返回(ps:呼叫join方法並不一定立刻執行另一個執行緒,只是當前執行緒進入等待,然後切換下一個執行緒)
import java.util.concurrent.atomic.AtomicInteger; /** * @author lhd */ public class BlockQueue { /** * 生產者鎖物件 */ private final Object addLock = new Object(); /** * 消費者鎖物件 */ private final Object deleteLock = new Object(); /** * 佇列總大小 */ private final Integer size = 30; /** * 資料存放 */ private Object[] queue = new Object[size]; /** * 存放的數量,使用AtomicInteger是因為普通的int遞增遞減操作會存在非原子性的問題,會使數量異常 */ private AtomicInteger count = new AtomicInteger(0); /** * 生產 * @param o 物件 */ public void add(Object o) { //獲取生產鎖,wait方法必須獲取到物件鎖後才可以呼叫,否則丟擲異常 synchronized (addLock){ //判斷是否超過佇列大小,超過則進入等待 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 + "生產了一個,現有數量" + i); } //如果佇列有資料,則呼叫notifyAll喚醒消費者 if (count.get() >= 1){ //notifyAll、notify都需要先獲取物件鎖,否則會丟擲異常 synchronized (deleteLock){ deleteLock.notifyAll(); } } } /** * 消費 * @return */ public Object poll(){ Object o; //先獲取物件鎖,和生產者類似 synchronized (deleteLock){ //佇列裡沒有資料則等待 while (count.get() <= 0){ try { deleteLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //獲取資料 o = queue[count.get()]; //遞減 int i = count.decrementAndGet(); String name = Thread.currentThread().getName(); System.out.println(name + "消費了一個,現有數量" + i); } //如果佇列沒有滿,則可以喚醒生產者 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(); } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。