线程通信-等待和唤醒机制和锁(Lock)机制
来源:互联网 发布:推广数据留言 编辑:程序博客网 时间:2024/05/21 08:00
生产者和消费者案例分析:
经典的生产者和消费者案例(Producer/Consumer):
分析案例:
1):生产者和消费者应该操作共享的资源(实现方式来做).
2):使用一个或多个线程来表示生产者(Producer).
3):使用一个或多个线程来表示消费者(Consumer).
生产者消费者的示意图:
为什么生产者不直接把数据给消费者,而是先把数据存储到共享资源中,然后,消费者再从共享资源中取出数据,再消费.
在这里体现了面向对象的设计理念:低耦合.
高(紧)耦合:直接使用生产者把肉包子给消费者,那么生产者中得存在消费者的引用,同理,消费者要消费生产者生产的肉包子,消费者中也得存在生产者对象的引用.例子: 主板和集成显卡.
低(松)耦合:使用一个中间对象,屏蔽了生产者和消费者直接的数据交互. 例子:主板和独立显卡.
高(紧)耦合:
//生产者public class Producer{ private Consumer con;//消费者对象}//消费者public class Consumer{ private Producer pro;//消费者对象}
低(松)耦合:
//共享资源public class ShareResource{}//生产者public class Producer{ private ShareResource resource;//共享资源对象}//消费者public class Consumer{ private ShareResource resource;//共享资源对象}
实现生产者和消费者案例
生产者:
//生产者生产数据public class Producer implements Runnable{private ShareResource resource = null;public Producer(ShareResource resource){this.resource = resource;}public void run() {for(int i = 0; i < 50; i++){if(i % 2 == 0){resource.push("春哥", "男");}else{resource.push("凤姐", "女");}}}}
消费者:
//消费者消费类public class Consumer implements Runnable{private ShareResource resource = null;public Consumer(ShareResource resource){this.resource = resource;}public void run() {for(int i = 0; i < 50; i ++){resource.popup();}}}
共享资源类:
//生产者和消费者共同的资源对象public class ShareResource {private String name;private String gender; //一般用枚举来写性别,这里先用String/** * 生产者向共享资源存储数据 * @param name 生产者生产的姓名 * @param gender 生产者生产的性别 */public void push(String name,String gender){this.name = name;Thread.sleep(10);this.gender = gender;}/** * 消费者向共享资源获取数据 */ public void popup(){System.out.println(this.name + "-" + this.gender);}}
分析生产者和消费者案例存在的问题:
建议在生产姓名和性别之间以及在打印之前使用Thread.sleep(10);使效果更明显.
此时出现下面的情况:
问题1:出现姓别紊乱,即出现凤姐-男的情况.
生产者先生产出春哥哥-男,此时消费者没有消费,生产者继续生产出姓名为凤姐,此时消费者开始消费了.
解决方案:只要保证在生产姓名和性别的过程保持同步,中间不能被消费者线程进来取走数据.
可以使用同步代码块/同步方法/Lock机制来保持同步性.
问题2:重复出现凤姐-男和凤姐-女,应该出现生产一个数据,消费一个数据.
应该交替出现: 春哥哥-男-->凤姐-女-->春哥哥-男-->凤姐-女.....
解决方案: 得使用 等待和唤醒机制.
线程通信:不同的线程执行不同的任务,如果这些任务有某种关系,线程之间必须能够通信,协调完成工作.
等待和唤醒机制:
线程通信-wait和notify方法介绍:
java.lang.Object类提供类两类用于操作线程通信的方法.
wait():执行该方法的线程对象释放同步锁,JVM把该线程存放到等待池中,等待其他的线程唤醒该线程.
notify:执行该方法的线程唤醒在等待池中等待的任意一个线程,把线程转到锁池中等待.
notifyAll():执行该方法的线程唤醒在等待池中等待的所有的线程,把线程转到锁池中等待.
注意:上述方法只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException..
------------------------------------------
假设A线程和B线程共同操作一个X对象(同步锁),A,B线程可以通过X对象的wait和notify方法来进行通信,流程如下:
1:当A线程执行X对象的同步方法时,A线程持有X对象的锁,B线程没有执行机会,B线程在X对象的锁池中等待.
2:A线程在同步方法中执行X.wait()方法时,A线程释放X对象的锁,进入A线程进入X对象的等待池中.
3:在X对象的锁池中等待锁的B线程获取X对象的锁,执行X的另一个同步方法.
4:B线程在同步方法中执行X.notify()方法时,JVM把A线程从X对象的等待池中移动到X对象的锁池中,等待获取锁.
5:B线程执行完同步方法,释放锁.A线程获得锁,继续执行同步方法.
因此,生产者消费者问题中的共享资源对象类可改为:
//生产者和消费者共同的资源对象public class ShareResource {private String name;private String gender; //一般用枚举来写性别,这里先用Stringprivate boolean isEmpty = true;/** * 生产者向共享资源存储数据 * @param name 生产者生产的姓名 * @param gender 生产者生产的性别 */synchronized public void push(String name,String gender){try {while(!isEmpty){//isEmpty为false时,当前线程等待//if(!isEmpty)用if也可以达到效果,只是while更安全(至少判断两次)this.wait();}this.name = name;Thread.sleep(10);this.gender = gender;isEmpty = false;//设置共享资源不为空this.notify(); //唤醒其他任意一个线程,这里是唤醒一个消费者} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/** * 消费者向共享资源获取数据 */ synchronized public void popup(){try {while(isEmpty){//当isEmpty为true时,共享资源为空,消费者等待this.wait();Thread.sleep(10);}System.out.println(this.name + "-" + this.gender);isEmpty = true;//消费结束,资源应设为空this.notify();// 唤醒一个生产者} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
除了等待唤醒机制,也可以使用锁机制
线程通信-使用Lock和Condition接口:
wait和notify方法,只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException.
那么现在问题来了,Lock机制根本就没有同步锁了,也就没有自动获取锁和自动释放锁的概念.
因为没有同步锁,所以Lock机制不能调用wait和notify方法.
解决方案:Java5中提供了Lock机制的同时提供了处理Lock机制的通信控制的Condition接口.
--------------------------------------------------------------------
从Java5开始,可以:
1):使用Lock机制取代synchronized代码块和synchronized方法.
2):使用Condition接口对象的await,signal,signalAll方法取代Object类中的wait,notify,notifyAll方法.
共享资源类可改成:
//生产者和消费者共同的资源对象public class ShareResource {private String name;private String gender;private boolean isEmpty = true;private final Lock lock = new ReentrantLock();private final Condition condition = lock.newCondition();/** * 生产者向共享资源提供数据 * @param name 生产者生产的名字 * @param gender 性别 */public void push(String name,String gender){lock.lock();try {if(!isEmpty){condition.await();}this.name = name;Thread.sleep(10);this.gender = gender;isEmpty = false;condition.signal();} catch (InterruptedException e) {e.printStackTrace();}finally{lock.unlock();}}/** * 消费者从共享资源获取(消费)数据 */public void popoup(){lock.lock();try {if(isEmpty){condition.await();}Thread.sleep(10);System.out.println(name+"-"+gender);isEmpty = true;condition.signal();} catch (InterruptedException e) {e.printStackTrace();}finally{lock.unlock();}}}
- 线程通信-等待和唤醒机制和锁(Lock)机制
- 线程间通信、等待唤醒机制、生产者消费者问题(Lock,Condition)、停止线程和守护线程、线程优先级
- 多线程的等待唤醒机制和Lock锁
- 线程间通讯和等待唤醒机制
- 14.显式的锁机制,显式的等待唤醒机制--lock和condition
- Java线程间通信-等待唤醒机制
- 线程间通信--等待唤醒机制
- 线程间的通信------------等待唤醒机制
- 线程间通信之等待唤醒机制
- 线程间通信之等待唤醒机制
- 线程之间的通信--等待唤醒机制
- 线程通信和等待/唤醒
- 线程间通信:生产者消费者(等待唤醒机制)
- (51)线程间通信,等待唤醒机制
- 线程间通信 等待唤醒机制 wait notify notifyAll lock Condition唤醒 停止线程interrupt 守护线程setDaemon join yield
- java多线程之 生产者和消费者 线程间通信 等待与唤醒机制
- 线程等待唤醒机制
- 多线程__【线程间通信】【等待唤醒机制】【多生产多消费】【Lock&Condition接口】
- unity3d shader学习(2)-unity shader的结构
- android控件之TextView显示聊天室信息
- shell 关于取得参数的问题
- JAVA温习课堂13
- UML用例图
- 线程通信-等待和唤醒机制和锁(Lock)机制
- Java并发基础(五)-CountDownLatch、CyclocBarrier、Phaser的使用
- ImageLoader
- Java单例模式--饿汉式、懒汉式需要怎么写
- Almost Sorted Array(HDU 5532 单调递增子序列)
- 各种算法和数据结构的复杂度
- python数据结构学习笔记-2016-10-07-01-完善后的mydate.py
- HDU 5927 Auxiliary Set dfs(思维)
- flowlayoutlibrary源码释放(待续)