wait notify的正确使用

Wait notify

分析:

T1获得了锁,正在干活,调用wait方法,T1到休息室(Waitset)并释放锁
其他线程获得锁执行。T2获得锁,调用notify通知T1干活,T1就到EntryList(blocked)继续竞争锁

调用wait方法,就进入了waitset,变为waiting状态

blocked与waiting都是阻塞,不占用cpu时间片
分析:

在这里插入图片描述

API介绍:

obj.wait() 让进入obj监视器的线程到waitset等待(调用wait(0):无限制等待)
obj.wait(long timeout) :等待timeout ms,如果没有被唤醒,就不等待了,就继续执行该线程剩余代码

obj.notify() 在obj上正在等待的线程中挑一个唤醒
obj.notifyAll() 在obj上正在等待的线程全部唤醒

注意:必须获得obj对象的锁才能调用这几个方法

线程1 2 都调用wait方法,进入waiting状态
并释放锁,main获得锁可以叫醒线程1 2
notify:随机叫醒一个
notifyAll:全部叫醒

public class WaitNotify {
    final static Object obj = new Object();
    public static void main(String[] args) throws InterruptedException {

        //线程t1,
        new Thread(()->{
            synchronized (obj){
                System.out.println(Thread.currentThread().getName()+"执行...");
                try {
                    obj.wait();//让线程在obj上一直等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"执行其他代码");
            }
        },"t1").start();


       //线程t2
        new Thread(()->{
            synchronized (obj){
                System.out.println(Thread.currentThread().getName()+"执行...");
                try {
                    obj.wait();//t2获得锁,进入等待状态
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"执行其他代码");
            }
        },"t2").start();


        Thread.sleep(2000);


        System.out.println("主线程唤醒其他线程");


        synchronized (obj){
           //主线程获得锁,调用唤醒等待状态的线程的方法
            obj.notify();  //唤醒obj上的一个线程
            //obj.notifyAll();//唤醒obj上所有的等待线程
        }
    }
}

sleep(long n) wait(long n)区别

sleep() 是Thread的静态方法,wait()是Object的方法
sleep 不强制和synchronized配合使用。wait强制和synchronized一起用
sleep在睡眠的时候不释放锁,wait释放

例子:
//wait的时候,T释放了锁,所以main线程马上获得了锁
//sleep的时候,T没有释放锁,main线程不能获得锁

public class SleepWait {
    private final static Object obj=new Object();
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            synchronized (obj){
                try {
                   // Thread.sleep(20000);  
                    obj.wait(20000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();


        Thread.sleep(1000);

       //wait的时候,T释放了锁,所以main线程马上获得了锁
       //sleep的时候,T没有释放锁,main线程不能获得锁
        synchronized (obj){   
            System.out.println("主线程获得锁");
        }
    }
}

wait notify的正确使用姿势

public class WaitNotify01 {
    private final static  Object ob = new Object();
    private static Boolean hasc=false;


    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            synchronized (ob){
                System.out.println("有烟吗");
                if(!hasc){
                    System.out.println("没有烟,休息一下");
                    try {
                        ob.wait();//释放锁,其他线程可以使用锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("有烟吗");
                if(hasc){
                    System.out.println("小南开始干活");
                }


            }
        }).start();


        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                synchronized (ob){ //小南休息的时候释放了锁,可以正常干活
                    System.out.println("其他人开始干活");
                }
            }).start();
        }


        Thread.sleep(1000);


        new Thread(()->{
            synchronized (ob){
                System.out.println("送来了");
                hasc=true;
                ob.notify();//叫醒小南
            }
        }).start();


    }
}

在这里插入图片描述
问题:万一waitset中 不止小南一个,怎么办?
如果错误唤醒,就是虚假唤醒

比如:

public class WaitNotify02 {
    private final static  Object ob = new Object();
    private static Boolean hasc=false;
    private static Boolean hasw =false;


    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            synchronized (ob){
                System.out.println("有烟吗");
                if(!hasc){
                    System.out.println("没有烟,休息一下");
                    try {
                        ob.wait();//释放锁,其他线程可以使用锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("有烟吗");
                if(hasc){
                    System.out.println("有烟了小南开始干活");
                }else {
                    System.out.println("没有烟,为什么叫我?");
                }


            }
        }).start();


        new Thread(()->{
            synchronized (ob){
                System.out.println("有外卖吗?");
                if(!hasw){
                    System.out.println("没有外卖,休息一下");
                    try {
                        ob.wait();//释放锁,其他线程可以使用锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("有外卖吗");
                if(hasw){
                    System.out.println("有外卖小女开始干活");
                }else {
                    System.out.println("没有外卖,为什么叫我");
                }


            }
        }).start();




        Thread.sleep(1000);


        new Thread(()->{
            synchronized (ob){
                System.out.println("外卖到了。。。");
                hasw=true;
                ob.notify();//叫醒小女
            }
        }).start();


    }
}

此时随机叫醒一个,叫醒了小南,但是我们想要叫醒小女
在这里插入图片描述
如果调用notifyAll:则全部会唤醒,小南小女全部被唤醒。但是不需要叫醒小南
在这里插入图片描述
改进:
可以用while替换if 就可以解决这个问题

public class WaitNotify03 {
    private final static  Object ob = new Object();
    private static Boolean hasc=false;
    private static Boolean hasw =false;


    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            synchronized (ob){
                System.out.println("有烟吗");
                while (!hasc){
                    System.out.println("没有烟,休息一下");
                    try {
                        ob.wait();//释放锁,其他线程可以使用锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("有烟吗");
                if(hasc){
                    System.out.println("有烟了小南开始干活");
                }else {
                    System.out.println("没有烟,为什么叫我?");
                }


            }
        }).start();


        new Thread(()->{
            synchronized (ob){
                System.out.println("有外卖吗?");
                while (!hasw){
                    System.out.println("没有外卖,休息一下");
                    try {
                        ob.wait();//释放锁,其他线程可以使用锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("有外卖吗");
                if(hasw){
                    System.out.println("有外卖小女开始干活");
                }else {
                    System.out.println("没有外卖,为什么叫我");
                }


            }
        }).start();




        Thread.sleep(1000);


        new Thread(()->{
            synchronized (ob){
                System.out.println("外卖到了。。。");
                hasw=true;
                ob.notifyAll();//叫醒小女
            }
        }).start();


    }
}

在这里插入图片描述

总结正确使用方式:

synchronized(lock){     
  while(条件不成立){     
        lock.wait();     
    }     
          //干活
  }
      //另一个线程
      synchronized(lock){  
           lock.notifyAll();
     }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值