【进阶】 wait sleep

2021-08-05  本文已影响0人  lconcise

不同:

  1. wait会释放锁,而sleep不会释放锁
  2. wait只能在同步方法和同步代码块中使用,而sleep任何地方都可以

相同点:都会让渡CPU执行时间,等待再次调度

1. lost wake up 问题

如果wait 不在同步方法或者同步代码块中使用,运行代码会直接报错。

    public static void main(String[] args) throws Exception{
        Object obj = new Object();
        obj.wait();
    }
Exception in thread "main" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at top.lconcise.practice.demo.NodeDemo.main(NodeDemo.java:11)

事情得从一个多线程编程里面臭名昭著的问题"Lost wake-up problem"说起。

这个问题并不是说只在Java语言中会出现,而是会在所有的多线程环境下出现。

生产者消费之的代码:
生产者伪代码:

count+1;
notify();

消费者伪代码:

while(count<=0){
   wait()
}
count--
image.png

解决该问题,就需要保证这一系列操作的原子性,在同步方法或同步代码中执行,可以保证原子性。

2. wait notify 原理

  1. 调用wait() 首先会获取监视器锁,获得成功后,会让线程进入等待状态进入等待队列并且释放锁;
  2. 然后当其他线程调用notify或者notifyall以后,会选择从等待队列中唤醒任意一个线程
  3. 而执行完notify方法以后,并不会立马唤醒线程,原因是当前线程仍然持有这把锁,处于等待状态的线程无法获得锁。必须要等到当前的线程执行完按monitorexit指令之后,也就是被释放之后,处于等待队列的线程就可以开始竞争锁了。

所以 wait 方法要做两件事

  1. 释放当前对象的锁
  2. 使得当前线程进入阻塞队列
    而这些操作都和监视器是相关的,所以wait必须要获得一个监视器锁,只在synchronized里面,才能明确锁。

放在同步块中是为了多线程并发处理,大家按照顺序依次合理干活,不要造成死锁饥饿现象,但是sleep()方法就是想让当前线程进入阻塞状态,不要干活,我也不释放我已经拥有的锁,等到sleep()的时间到了,我再进入就绪态,等待cpu派活给我。sleep根本就不存在多线程并发访问问题,所以就不需要放在同步块中。

wait方法是让当前线程释放锁。然后让别的线程继续竞争。阻塞线程
notify通知 唤醒一个阻塞的线程 随机通知一个
这些都应该属于资源锁的动作,而作为锁,java中锁一般锁谁?锁的是对象,因为对象是资源,是我们需要操作的实体,而Object是所有对象的父类

sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定。

https://www.cnblogs.com/myseries/p/13903051.html

上一篇下一篇

猜你喜欢

热点阅读