Java wait和notifyAll实现简单的阻塞队列

 更新时间:2019年10月19日 11:14:58   作者:我不是一个小菜鸟  
这篇文章主要介绍了Java wait和notifyAll实现简单的阻塞队列,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

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();
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • java中lambda表达式的分析与具体用法

    java中lambda表达式的分析与具体用法

    这篇文章主要给大家介绍了关于java中lambda表达式具体用法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • java 通过 SmbFile 类操作共享文件夹的示例

    java 通过 SmbFile 类操作共享文件夹的示例

    这篇文章主要介绍了java 通过 SmbFile 类操作共享文件夹,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • Java数据类型转换实例解析

    Java数据类型转换实例解析

    这篇文章主要介绍了Java数据类型转换实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Maven dependency plugin使用心得总结

    Maven dependency plugin使用心得总结

    这篇文章主要给大家介绍了关于Maven dependency plugin使用心得的相关资料,Maven是一个常用的Java build Manager,使用Maven可以很好的对Java Project的dependency进行管理,需要的朋友可以参考下
    2023-10-10
  • spring boot 如何指定profile启动

    spring boot 如何指定profile启动

    这篇文章主要介绍了spring boot 如何指定profile启动的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • idea2020.1.3 手把手教你创建web项目的方法步骤

    idea2020.1.3 手把手教你创建web项目的方法步骤

    这篇文章主要介绍了idea 2020.1.3 手把手教你创建web项目的方法步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • 实例详解MyBatis-plus自动填充功能

    实例详解MyBatis-plus自动填充功能

    每次对数据进行新增、删除、修改时都需要对这些字段进行设置,虽然新增时间和修改时间可以使用数据库的时间,但是新增人和修改人就不能使用这样的功能,下面小编给大家介绍下MyBatis-plus自动填充功能的实例代码,感兴趣的朋友一起看看吧
    2022-01-01
  • Java多线程饥饿与公平介绍及代码示例

    Java多线程饥饿与公平介绍及代码示例

    这篇文章主要介绍了Java多线程饥饿与公平介绍及代码示例,分析饥饿产生的原因以及相关实例,然后就在java中实现公平性问题做了详细解析,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Spring计时器StopWatch的具体使用

    Spring计时器StopWatch的具体使用

    本文主要介绍了Spring计时器StopWatch的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • netty中的IO、NIO、AIO使用详解

    netty中的IO、NIO、AIO使用详解

    这篇文章主要介绍了netty中的IO、NIO、AIO使用详解,本文会说明各种IO的特点、分别解决了什么样的问题做一个分析阐述,并结合Java代码例子来辅助理解,像这些的历史演进和详细的底层原理网上很多,所以我们只站在应用层,使用者的角度去分析,需要的朋友可以参考下
    2023-12-12

最新评论