java并发(等待/通知机制)
来源:互联网 发布:sql一行多列 sum 求和 编辑:程序博客网 时间:2024/06/05 11:19
生产者与消费者的java实现及注意事项
生产者消费者问题是研究多线程绕不开的经典问题,主要是有一块缓冲区作为仓储,生产者向里面生产资源,消费者消费其中的资源,一旦资源为空,则消费者通知生产者生产资源,一旦仓储中有资源,则生产者通知消费者消费资源。解决生产者消费者问题主要有两种思想:(1)采用信号或锁机制使生产者与消费者之间同步。(2)在生产者与消费者之间建立一个管道。采用同步的方法主要包括:
(1)wait/notify机制
(2)await/signal机制
(3)LinkedBlockingQueue阻塞队列机制
一.采用wait/notify机制
wait方法是指当前执行代码的线程进行等待,将当前线程置入“预执行队列”,直到调用notify方法或者中断线程位置,在调用wait方法之前,必须获得该对象的对象锁,即wait方法必须在同步方法或同步代码块中使用,调用wait方法或,线程会释放对象锁,当调用notify(notifyall)方法后,与其他线程重新竞争获得对象锁。wait()方法的调用不需要捕捉异常。
notify()方法同wait()方法一样是Object类的方法,也需要在同步方法或者同步代码块中执行,代用该方法之前也需要获得给对象的锁,调用该方法后,会通知可能等待该对象锁的其他进程,如果有多个线程等待该对象锁,会随机挑选一个wait的线程通知其notify,当调用notify方法后,wait的并不会立即获取对象锁,只有当notify所在的同步代码块执行完后,wait的线程才会来获取对象锁。wait和notify方法是一对一对应的,一次notify只能唤醒一个wait。
a.一生产者与一消费者
生产者:public class Producer extends Thread{ private String lock;//存储对象锁 Producer(String lock){ this.lock = lock; } public void run(){ while(true){ try{ synchronized(lock){ if(!Value.value.equals("")){//值如果改变,则通知消费者消费,生产者等待,否则改变存储值 lock.wait(); } String value = System.currentTimeMillis()+Thread.currentThread().getName(); Value.value = value; System.out.println("设置的value值是"+value); lock.notify(); Thread.sleep(1000); //设置睡眠时间 } }catch(Exception e){ e.printStackTrace(); } } }}消费者:package com.org.wh.onetoone;import java.util.LinkedList;public class Consumer extends Thread{ private String lock;//存储对象锁 Consumer(String lock){ super(); this.lock = lock; } public void run(){ while(true){ try{ synchronized(lock){ if(Value.value.equals("")){//存储值是否为“”,是则消费者等待,通知生产者生产,否则消费者消费同时将存储值恢复 lock.wait(); } System.out.println("get的value值"+Value.value); Value.value = ""; lock.notify(); Thread.sleep(1000);//设置睡眠时间 } }catch(Exception e){ e.printStackTrace(); } } }}存储值的java代码:public class Value { //不能为private public static String value="";}Main函数:import java.util.LinkedList;public class Main { public static void main(String[] args) { String lock = Value.value;//存储对象 Producer p = new Producer(lock); Consumer c = new Consumer(lock); p.start(); c.start(); }}
b.多生产者与多消费者
生产者:import java.util.LinkedList;public class Producer extends Thread{ private LinkedList<String> lock;//存储对象 Producer(LinkedList<String> lock){ this.lock = lock; } @Override public void run() { while(true){ try{ synchronized(lock){ if(Storage.list.size()==Storage.Max){//判断存储是否满,是则生产者等待,否则生产者生产同时通知消费者消费 lock.wait(); System.out.println(Thread.currentThread().getState()); } System.out.println("存储数据"+System.currentTimeMillis()+Thread.currentThread().getName()+" "+Storage.list.size()); Storage.list.add(System.currentTimeMillis()+Thread.currentThread().getName()); lock.notify(); Thread.sleep(100); } }catch(Exception e){ e.printStackTrace(); } } }}消费者:import java.util.LinkedList;public class Consumer extends Thread { private LinkedList<String> lock;//存储对象 Consumer(LinkedList<String> lock){ this.lock = lock; } @Override public void run() { while(true){ try{ synchronized(lock){ if(Storage.list.size()==0){//判断存储是否为空,是则通知生产者生产,消费者等待 lock.wait(); System.out.println(Thread.currentThread().getState()+" "+1); } System.out.println("获取数据"+Storage.list.remove()+" "+Storage.list.size()); lock.notify(); Thread.sleep(100); } }catch(Exception e){ } } }}存储:import java.util.LinkedList;public class Storage { public static LinkedList<String> list = new LinkedList<>(); public static int Max = 40;}主线程:package com.org.wh.duotoduo;import java.util.LinkedList;public class Main { public static void main(String[] args) { LinkedList<String> lock = Storage.list;//获取存储对象 Producer p = new Producer(lock); p.start(); Producer p1 = new Producer(lock); p1.start(); Producer p2 = new Producer(lock); p2.start(); Producer p3 = new Producer(lock); p3.start(); Producer p4 = new Producer(lock); p4.start(); Consumer c = new Consumer(lock); c.start(); Consumer c1 = new Consumer(lock); c1.start(); Consumer c2 = new Consumer(lock); c2.start(); Consumer c3 = new Consumer(lock); c3.start(); Consumer c4 = new Consumer(lock); c4.start(); }}
注意:多消费者与多生产者模式中会出现如下的结果:
原因:可能是在notify唤醒的是异类,而非同类,久而久之可能会造成假死状态,可以使用notifyall方法来解决。
二.阻塞队列实现
java.util.concurrent包是在jdk1.5新引进的java并发包,对java多线程进行并发处理设计,尽量避免使用synchronized,提供并发性的可能。阻塞队列是在java并发包中提供的,主要包含以下几种:
(1)ArrayBlockingQueue:一种基于数组实现的阻塞队列,具有先进先出性质,在创建时必须指定大小。
(2)LinkedBlockingQueue :一种基于链表实现的阻塞队列,具有先进先出性质,在创建时不指定大小时,默认长度为Integer.MAX_VALUE。
(3)PriorityBlockingQueue : 一种基于优先级的阻塞队列,优先级高的先出队列,低的后出队列,同时该队列是一个无界队列(前两个都有界)。
(4)DelayQueue : 基于PriorityBlockingQueue实现的队列,具有延时性,只有到达时间限制后才能从队列中取出,该队列是一个无界队列,向队列中存入元素不会阻塞,但消费元素会有延迟(阻塞)。
阻塞队列与非阻塞队列包含方法的比较:
(1)非阻塞队列具有add,remove,poll,offer,peek等方法,add与remove方法在插入成功时返回true,否则抛出异常,而poll,offer,peek方法在操作失败时返回false,所以在使用非阻塞队列时建议使用poll,offer,peek方法,会返回结果。
(2)阻塞队列包含put,offer,poll,take方法。put,take方法在操作成功时返回true,否则等待;offer,poll方法在操作成功时返回true,否则等待一定时间,一定时间后还是无法操作返回false。
代码:
生产者:public class Producer extends Thread { public void run() { while(true){ try{ if(Storage.block.size()<Storage.Max){//队列为满时生产 Storage.block.put("1"); System.out.println("当前存放的数量"+Storage.block.size()); Thread.sleep(1000); } }catch(Exception e){ e.printStackTrace(); } } }}消费者:public class Consumer extends Thread { @Override public void run() { while(true){ try{ Storage.block.take(); System.out.println("当前存放的数量"+Storage.block.size()); Thread.sleep(1000); }catch(Exception e){ e.printStackTrace(); } } }}
- java并发(等待/通知机制)
- 《Java并发编程的艺术》读书笔记:等待/通知机制
- Java的等待通知机制
- java并发编程 之 Condition(等待和通知)
- java并发基础--等待通知模式
- Java等待/通知机制:生产者-消费者问题
- java多线程的等待和通知机制
- java线程同步的等待通知机制
- java线程等待/通知机制及中断
- java多线程系列(三)---等待通知机制
- java多线程系列(三)---等待通知机制
- 3.1等待/通知机制(wait/notify)
- 多线程 等待/通知机制
- 等待/通知机制:
- 通知等待机制
- Java并发编程3-等待、通知和中断
- Java 并发 线程间通信 等待/通知的经典范式
- Java高并发--等待通知和挂起继续执行
- 第十三周项目4 立体类族共有的抽象类
- Javascript apply, call this
- MyBatis学习总结——实现关联表查询
- 第十三周项目—阅读、修改和运行关于交通工具类的程序(2)
- cs231n 卷积神经网络与计算机视觉 2 SVM softmax
- java并发(等待/通知机制)
- 【Android】Eclipse上string.xml发生Found text“ ” where item tag is expected错误,如何解决
- 超强、超详细Redis数据库入门教程
- Node.JS连接数据库
- 条件语句 四元式
- iOS-OC-UITableViewCell分割线自定义
- Innodb锁机制:Next-Key Lock 浅谈
- 多态事例
- 电脑蓝牙连接后串口有传出和传入,如何区别