大厂之路一由浅入深、并行基础、源码分析一等待W、通知N

  • Object.java中,定义了wait(), notify()和notifyAll()等接口,这意味着任何对象都可以调用这几个方法。
  • wait():
    • 作用: 让当前线程放弃CPU(sleep不会放其)、共享资源,处于等待(阻塞)状态,直到其他线程调用该同步监视器的notify(),notifyAll()方法来唤醒该线程,进入就绪状态
    • wait(): 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
    • wait(long timeout): 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者 超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
    • wait(long timeout, int nanos): 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者已超过某个实际时间量”,或者其 他某个线程中断当前线程,当前线程被唤醒(进入“就绪状态”)。
    • 源码分析:
      • 在这里插入图片描述

  • notify()、notifyAll():
    • 作用:唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
    • notify() : 唤醒在此对象监视器上等待的单个线程。
    • notifyAll(): 唤醒在此对象监视器上等待的所有线程。
    • 源码分析:
      • 在这里插入图片描述

  • wait()、notify()引起的问题?
    • 如果一个线程调用了object.wait()方法,那么它就会进入object对象的等待队列,这个等待队列中,可能会有很多线程,因为系统运行多个线程同时等待某一个对象。当notify()调用,它会从等待队列中随机选择一个线程,将其唤醒。这时候就会产生 饥饿,这时候需要公平锁。
  • wait()、notify()的应用限制?
    • Java.lang.Object提供的这几个方法只有在synchronized方法或代码块中才能使用,否则会报出java.lang.IllegalMonitorStateException异常
  • wait()和sleep()有什么区别?
    • Object–>wait() , Thread–>sleep() 一个属于Object,一个属于Thread
    • Object.wait()和Thread.sleep()方法都可以让线程等待若干时间,但wait()可以被notify()唤醒
    • Object.wait()会释放目标对象的锁,Thread.sleep()不会释放任何资源(CPU)
  • 为什么notify(), wait()等函数定义在Object中,而不是Thread中? (面经中有更好的解答)
    • Object中的 wait(), notify() 等函数,和synchronized一样,会对“对象的同步锁”进行操作
    • wait()会使“当前线程”等待,因为线程进入等待状态,所以线程应该释放它锁持有的“同步锁”,否则其它线程获取不到该“同步锁”而无法运行!
    • 等待线程可以被notify()或notifyAll()唤醒。
    • 现在,请思考一个问题:notify()是依据什么唤醒等待线程的? 或者说,wait()等待线程和notify()之间是通过什么关联起来的?答案是:依据“对象的同步锁”。
    • 负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。
    • 虽然,等待线程被唤醒;但是,它不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后,等待线程才能获取到“对象的同步锁”进而继续运行。
    • 总之,notify(), wait()依赖于“同步锁”,而 “同步锁”是对象锁持有并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因

  • 代码案例:
package com.wwj.text;

public class  WaitTest{
    final static Object obj = new Object();
    public static class T1 extends  Thread{
        @Override
        public void run() {
            synchronized (obj){  //获得监听器
                System.out.println(System.currentTimeMillis() + ":T1.start");
                try{
                    System.out.println(System.currentTimeMillis()+"T1 wait for object");
                    obj.wait();  //释放监听器
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis()+"T1.end");
            }
        }
    }
    public  static class  T2 extends Thread{
        @Override
        public void run() {
            synchronized (obj){
                System.out.println(System.currentTimeMillis()+"T2.start!notify one thread");
                obj.notify();
                System.out.println(System.currentTimeMillis()+"T2 end!");
                try{
                    Thread.sleep(2000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args){
        Thread t1 = new T1();
        Thread t2 = new T2();
        t1.start();
        t2.start();
    }
}
1622026562944:T1.start
1622026562956T1 wait for object
1622026562957T2.start!notify one thread
1622026562957T2 end!
1622026564970T1.end

案例说明:由结果:1622026562957T2 end! 1622026564970T1.end可知,notify()后等待线程不能立即执行,必须等到唤醒线程释放对象的同步锁才可

  • 在这里插入图片描述注意notify()后的操作!
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值