溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么在Java中使用wait和notifyAll實(shí)現(xiàn)阻塞隊(duì)列

發(fā)布時(shí)間:2021-05-27 18:09:27 來源:億速云 閱讀:182 作者:Leah 欄目:編程語言

本篇文章給大家分享的是有關(guān)怎么在Java中使用wait和notifyAll實(shí)現(xiàn)阻塞隊(duì)列,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

import java.util.concurrent.atomic.AtomicInteger;
/**
 * @author lhd
 */
public class BlockQueue {
	/**
  * 生產(chǎn)者鎖對(duì)象
  */
	private final Object addLock = new Object();
	/**
  * 消費(fèi)者鎖對(duì)象
  */
	private final Object deleteLock = new Object();
	/**
  * 隊(duì)列總大小
  */
	private final Integer size = 30;
	/**
  * 數(shù)據(jù)存放
  */
	private Object[] queue = new Object[size];
	/**
  * 存放的數(shù)量,使用AtomicInteger是因?yàn)槠胀ǖ膇nt遞增遞減操作會(huì)存在非原子性的問題,會(huì)使數(shù)量異常
  */
	private AtomicInteger count = new AtomicInteger(0);
	/**
  * 生產(chǎn)
  * @param o 對(duì)象
  */
	public void add(Object o) {
		//獲取生產(chǎn)鎖,wait方法必須獲取到對(duì)象鎖后才可以調(diào)用,否則拋出異常
		synchronized (addLock){
			//判斷是否超過隊(duì)列大小,超過則進(jìn)入等待
			while (count.get() >= size){
				try {
					addLock.wait();
				}
				catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			//存放一個(gè)
			queue[count.get()] = o;
			//遞增
			int i = count.incrementAndGet();
			//打印一下日志
			String name = Thread.currentThread().getName();
			System.out.println(name + "生產(chǎn)了一個(gè),現(xiàn)有數(shù)量" + i);
		}
		//如果隊(duì)列有數(shù)據(jù),則調(diào)用notifyAll喚醒消費(fèi)者
		if (count.get() >= 1){
			//notifyAll、notify都需要先獲取對(duì)象鎖,否則會(huì)拋出異常
			synchronized (deleteLock){
				deleteLock.notifyAll();
			}
		}
	}
	/**
  * 消費(fèi)
  * @return
  */
	public Object poll(){
		Object o;
		//先獲取對(duì)象鎖,和生產(chǎn)者類似
		synchronized (deleteLock){
			//隊(duì)列里沒有數(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 + "消費(fèi)了一個(gè),現(xiàn)有數(shù)量" + i);
		}
		//如果隊(duì)列沒有滿,則可以喚醒生產(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();
	}
}

效果:其實(shí)這個(gè)遞增遞減操作和打印操作也不是原子操作

怎么在Java中使用wait和notifyAll實(shí)現(xiàn)阻塞隊(duì)列

依次打印線程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();
 }
}

以上就是怎么在Java中使用wait和notifyAll實(shí)現(xiàn)阻塞隊(duì)列,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI