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

wait,会使调用的线程进入等待状态,会释放所持有的对象锁(调用的时候也必须先获取到锁,否则会抛出异常 IllegalMonitorStateException)

notifyAll、notify,会去唤醒应当前对象而等待的线程,(调用的时候也必须先获取到锁,否则会抛出异常 IllegalMonitorStateException)

顺便也记录一下join方法,调用join方法,会使当前线程进入等待,如果没有设置等待时间,就会等待另一个线程执行完成才返回(ps:调用join方法并不一定立刻执行另一个线程,只是当前线程进入等待,然后切换下一个线程)

  1 import java.util.concurrent.atomic.AtomicInteger;
  2
  3 /**
  4  * @author lhd
  5  */
  6 public class BlockQueue {
  7
  8     /**
  9      * 生产者锁对象
 10      */
 11     private final Object addLock = new Object();
 12
 13     /**
 14      * 消费者锁对象
 15      */
 16     private final Object deleteLock = new Object();
 17
 18     /**
 19      * 队列总大小
 20      */
 21     private final Integer size = 30;
 22
 23     /**
 24      * 数据存放
 25      */
 26     private Object[] queue = new Object[size];
 27
 28     /**
 29      * 存放的数量,使用AtomicInteger是因为普通的int递增递减操作会存在非原子性的问题,会使数量异常
 30      */
 31     private AtomicInteger count = new AtomicInteger(0);
 32
 33     /**
 34      * 生产
 35      * @param o 对象
 36      */
 37     public void add(Object o) {
 38         //获取生产锁,wait方法必须获取到对象锁后才可以调用,否则抛出异常
 39         synchronized (addLock){
 40
 41             //判断是否超过队列大小,超过则进入等待
 42             while (count.get() >= size){
 43                 try {
 44                     addLock.wait();
 45                 } catch (InterruptedException e) {
 46                     e.printStackTrace();
 47                 }
 48             }
 49             //存放一个
 50             queue[count.get()] = o;
 51             //递增
 52             int i = count.incrementAndGet();
 53             //打印一下日志
 54             String name = Thread.currentThread().getName();
 55             System.out.println(name + "生产了一个,现有数量" + i);
 56         }
 57         //如果队列有数据,则调用notifyAll唤醒消费者
 58         if (count.get() >= 1){
 59             //notifyAll、notify都需要先获取对象锁,否则会抛出异常
 60             synchronized (deleteLock){
 61                 deleteLock.notifyAll();
 62             }
 63         }
 64
 65     }
 66
 67     /**
 68      * 消费
 69      * @return
 70      */
 71     public Object poll(){
 72         Object o;
 73         //先获取对象锁,和生产者类似
 74         synchronized (deleteLock){
 75             //队列里没有数据则等待
 76             while (count.get() <= 0){
 77                 try {
 78                     deleteLock.wait();
 79                 } catch (InterruptedException e) {
 80                     e.printStackTrace();
 81                 }
 82             }
 83             //获取数据
 84             o = queue[count.get()];
 85             //递减
 86             int i = count.decrementAndGet();
 87             String name = Thread.currentThread().getName();
 88             System.out.println(name + "消费了一个,现有数量" + i);
 89         }
 90         //如果队列没有满,则可以唤醒生产者
 91         if (count.get() < size){
 92             //需要先获取到锁
 93             synchronized (addLock){
 94                 addLock.notifyAll();
 95             }
 96         }
 97         return o;
 98     }
 99
100     /**
101      * 简单的测试
102      * @param args
103      */
104     public static void main(String[] args) {
105         BlockQueue blockQueue = new BlockQueue();
106         Thread t1 = new Thread(()-> {while (true){blockQueue.add(new Object());}});
107         Thread t2 = new Thread(()-> {while (true){blockQueue.add(new Object());}});
108         Thread t3 = new Thread(()-> {while (true){blockQueue.add(new Object());}});
109         Thread t4 = new Thread(()-> {while (true){blockQueue.poll();}});
110         Thread t5 = new Thread(()-> {while (true){blockQueue.poll();}});
111         Thread t6 = new Thread(()-> {while (true){blockQueue.poll();}});
112         t1.start();
113         t2.start();
114         t3.start();
115         t4.start();
116         t5.start();
117         t6.start();
118     }
119
120 }

效果:其实这个递增递减操作和打印操作也不是原子操作,

依次打印线程1,2,3

 1 /**
 2  * @author lhd
 3  */
 4 public class JoinTest {
 5
 6
 7     public static void main(String[] args) throws InterruptedException {
 8         Thread t1 = new Thread(() -> System.out.println(1));
 9         Thread t2 = new Thread(()-> System.out.println(2));
10         Thread t3 = new Thread(()-> System.out.println(3));
11
12         t1.start();
13         t1.join();
14
15         t2.start();
16         t2.join();
17
18         t3.start();
19         t3.join();
20
21     }
22
23 }

原文地址:https://www.cnblogs.com/hdllhd/p/11699738.html

时间: 2024-10-10 03:18:04

Java wait和notifyAll的使用,简单的阻塞队列实现的相关文章

java condition 实现简单的阻塞队列

上一篇文章介绍了condition的使用方法 https://www.cnblogs.com/liumy/p/11563772.html 这一篇文章介绍如何用condition来实现一个简单的阻塞队列 消费者 生产者模式. 消费者 生产者模式就是 生产者生产某些对象,消费者来消费这些对象.其中用对象数组来保存这些对象,既然是数组,在初始化的时候需要指定数组的大小. 在生产者生产的时候需要检查数组是否已经满了,如果满了,那么生产者会被挂起,等到有消费者消费对象时,再进行生产. 当消费者消费的时候,

Java多线程与并发库高级应用之阻塞队列BlockingQueue

JDK1.5提供了阻塞队列接口BlockingQueue,它是一个有界阻塞队列.BlockingQueue实现是线程安全的,可以安全地与多个生产者和多个使用者一起使用. 使用时用其实现类 ArrayBlockingQueue,它一个由数组支持的有界阻塞队列.此队列按 FIFO(先进先出)原则对元素进行排序.队列的头部 是在队列中存在时间最长的元素.队列的尾部是在队列中存在时间最短的元素.新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素. 这是一个典型的"有界缓存区",固定

java消费者生产者模式及JDK之阻塞队列LinkedBlockingQueue实现

生产者消费者问题 (英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了两个共享固定大小缓冲区的线程--即所谓的"生产者"和"消费者"--在实际运行时会发生的问题.生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程.与此同时,消费者也在缓冲区消耗这些数据.该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空

跟我学Java多线程——线程池与阻塞队列

前言 上一篇文章中我们将ThreadPoolExecutor进行了深入的学习和介绍,实际上我们在项目中应用的时候很少有直接应用ThreadPoolExecutor来创建线程池的,在jdk的api中有这么一句话"但是,强烈建议程序员使用较为方便的 Executors 工厂方法Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收).Executors.newFixedThreadPool(int)(固定大小线程池)和Executors.newSingleT

java语言及其垃圾回收机制简单概述

 一.java 语言概述 Java 语言是一门纯粹的面向对象编程语言,它吸收了c++语言的各种优点.又摈弃了c++里难以理解的多继承,指针等概念因此Java语言具有功能强大和简单易用两个特征. Java语言的几个重要概念如下: J2ME:主要用于控制移动设备和信息家电等有限存储设备 J2SE:整个java技术的核心和基础, J2EE:java技术中应用最最广泛的部分,它提供了企业应用开发相关的完整的解决方案. API: 核心类库 JRE:运行Java程序所必须的环境的集合,包含JVM标准实现及J

java 堆 栈 方法区的简单分析

Java里的堆(heap)栈(stack)和方法区(method) 基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收.   引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 . 方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完成后从栈空间回收.局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收. 方法调用时传入的

Excel导出学习之道:Java Web利用POI导出Excel简单例子

采用Spring mvc架构: Controller层代码如下 [java] view plaincopy @Controller public class StudentExportController{ @Autowired private StudentExportService studentExportService; @RequestMapping(value = "/excel/export") public void exportExcel(HttpServletReq

Java中的异常处理机制的简单原理和应用。

异常是指java程序运行时(非编译)所发生的非正常情况或错误,与现实生活中的事件很相似,现实生活中的事件可以包含事件发生的时间.地点.人物.情节等信息,可以用一个对象来表示,Java使用面向对象的方式来处理异常,它把程序中发生的每个异常也都分别封装到一个对象来表示的,该对象中包含有异常的信息. Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception,Erro

java 中 “文件” 和 “流” 的简单分析

java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 //创建一个File 对象,检验文件是否存在,若不存在就创建然后对File package wfu; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.Scanner; pu