zoukankan      html  css  js  c++  java
  • 多线程(五)~ wait/notify机制(等待/通知)

    首先我们来看一张图,这张图描述了线程操作的几个步骤。

    图已经描述的很清楚了,这里除了wait()之外,其他的前面都已经接触过了。
    这一章我们主要来说一下和wait()相关的操作,其实和wait()相关的还有另外两个函数notity()和notifyAll()。
    这三个函数都是Object类里的方法
    wait():使调用此方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒
    notify():随机唤醒等待队列中等待同一个共享资源的“一个”线程,并使该线程退出等待队列,进入可运行状态,也就是说notofy()通知唤醒一个线程。
    notifyAll():使所有正在等待队列中等待同一个共享资源的“全部”线程从等待状态退出,进入可运行状态。
    注意:notify()和notifyAll()后并不是直接就释放锁的,而是等notify()后的代码执行完毕后才释放锁。而且这三个方法都必须在synchronize代码块里执行,否则会报错。
     
    每个对象都有两个队列,一个是就绪队列,一个是阻塞队列。就绪队列存储了将要获得锁的线程,阻塞队列存储了所有被阻塞的线程。一个线程被唤醒后,才会进入就绪队列,等待CPU的调度,反之,一个线程被wait()之后,线程就进入了阻塞队列,等待下一次被唤醒。
     
    线程会释放锁的三种情况:
    1.线程任务执行完毕,释放锁。
    2.线程调用wait()方法,释放锁。
    3.线程执行过程中发生异常,释放锁。
     
    生产-消费者模式:
    单生产者,单消费者demo:
     
    ①.生产者:
    1. package com.multiThread.bean;
    2. publicclass P {
    3. privateObject lock;
    4. public P(Object lock){
    5. this.lock = lock;
    6. }
    7. publicvoidSetValue(){
    8. try{
    9. synchronized(lock){
    10. if(!ValueObject.value.equals("")){
    11. lock.wait();
    12. }
    13. String value =System.currentTimeMillis()+"_"+System.nanoTime();
    14. System.out.println("set值为:"+ value);
    15. ValueObject.value = value;
    16. lock.notify();
    17. }
    18. }catch(Exception e){
    19. e.printStackTrace();
    20. }
    21. }
    22. }
    ②.消费者
    1. package com.multiThread.bean;
    2. publicclass C {
    3. privateObject lock;
    4. public C(Object lock){
    5. this.lock = lock;
    6. }
    7. publicvoid getValue(){
    8. try{
    9. synchronized(lock){
    10. if(ValueObject.value.equals("")){
    11. lock.wait();
    12. }
    13. System.out.println("get的值:"+ValueObject.value);
    14. ValueObject.value ="";
    15. lock.notify();
    16. }
    17. }catch(Exception e){
    18. e.printStackTrace();
    19. }
    20. }
    21. }
    ③.生产者线程类
    1. package com.multiThread.thread;
    2. import com.multiThread.bean.P;
    3. publicclassThreadPimplementsRunnable{
    4. private P p;
    5. publicThreadP(P p){
    6. this.p = p;
    7. }
    8. @Override
    9. publicvoid run(){
    10. while(true){
    11. p.SetValue();
    12. }
    13. }
    14. }
    ④.消费者线程类
    1. package com.multiThread.thread;
    2. import com.multiThread.bean.C;
    3. publicclassThreadCimplementsRunnable{
    4. private C c;
    5. publicThreadC(C c){
    6. this.c = c;
    7. }
    8. @Override
    9. publicvoid run(){
    10. while(true){
    11. c.getValue();
    12. }
    13. }
    14. }
    ⑤.测试类
    1. package com.multiThread.test.productionConsumption;
    2. import com.multiThread.bean.C;
    3. import com.multiThread.bean.P;
    4. import com.multiThread.thread.ThreadC;
    5. import com.multiThread.thread.ThreadP;
    6. /**
    7. * 等待、通知机制
    8. */
    9. publicclassProduceCustomTest{
    10. publicstaticvoid main(String[] args){
    11. Object lock =newObject();
    12. P p =new P(lock);
    13. C c =new C(lock);
    14. ThreadP tp =newThreadP(p);
    15. ThreadC tc =newThreadC(c);
    16. Thread t1 =newThread(tp);
    17. Thread t2 =newThread(tc);
    18. t1.start();
    19. t2.start();
    20. }
    21. }
    执行结果:
    1. set值为:1466176983137_22743411842275
    2. get的值:1466176983137_22743411842275
    3. set值为:1466176983137_22743412731096
    4. get的值:1466176983137_22743412731096
    5. set值为:1466176983137_22743412952232
    6. get的值:1466176983137_22743412952232
    7. set值为:1466176983137_22743413140860
    8. get的值:1466176983137_22743413140860
    9. .
    10. .
    11. .
    可见生产者和消费者是交替执行的。
    这里仅仅是单生产者和消费者。如果是多生产者和消费者会正常运行吗?
    答案是否定的。因为notify()之后是随机唤醒一个线程,如果生产者唤醒的是生产者,那么就会一直处于wait(),造成死锁。
    解决问题的方法:
        将notify()方法换成notifyAll()
     
     
     
     
     
     
     
     
     





  • 相关阅读:
    10.21SQL注入
    10.15计网相关
    10.11php+mysql
    10.10 接在10.8随笔中
    10.9 利用微信dll反弹shell复现
    10.8php续
    9.29 接9.27PHP相关
    java泛型
    java集合之Map接口
    java集合之Collection接口
  • 原文地址:https://www.cnblogs.com/douJiangYouTiao888/p/6473809.html
Copyright © 2011-2022 走看看