7_sleep和wait的比较

  • sleep和wait的区别

    (1) sleep是Thread类的静态方法,wait是Object类的非静态方法。

    注: sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep

    (2) sleep没有释放锁,而wait方法释放了锁

    (3) wait, notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用

  • (1) 所有对象都自动含有单一的锁。

    (2) JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。

    (3) 只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。

    (4) 每当任务离开一个synchronized(同步)方法,计数递减,当计数为0的时候,锁被完全释放,此时别的任务就可以使用此资源。

  • 锁池和等待池

    (1) 在Java中,每个对象都有两个池,锁(monitor)池和等待池

    (2) 锁池

    假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中

    (3) 等待池

    假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(因为wait()方法必须出现在synchronized中,这样自然在执行wait()方法之前线程A就已经拥有了该对象的锁),同时线程A就进入到了该对象的等待池中

    如果另外的一个线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,准备争夺锁的拥有权;

    如果另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池.

    (4) 示例

      线程A,B,C,D都在调用一个对象的非静态synchronized方法(同一个对象锁this),此时线程A是锁的主人,此时锁池中有B,C,D三个线程,等待池为空;
    
      现在A调用wait()方法,此时锁池为B,C,D,等待池为A;
    
      假设系统调度线程B获得锁,此时锁池为C,D,等待池为A;
    
      现在B也调用wait()方法,此时锁池为C,D, 等待池为A,B;
    
      假设系统调度线程C获得锁,此时锁池为D,等待池为A,B;
    
      如果C此时调用notify(),则随机选择等待池中的一个线程进入锁池,可能的情况是锁池为A,D,等待池为B; 锁池为B,D,等待池为A;
    
      如果C此时调用notifyAll(),则等待池中等待这个对象锁的线程全部进入锁池,则锁池为A,B,D,等待池为空
    

    (5) 只有锁池中的线程会竞争锁。换句话说,等待池中的线程只有先进入锁池,才有了竞争锁的权利,之前它们只能等待notify(),notifyAll(),certainThread.interrupt(),到达等待时间了等几种情况,从等待池进入锁池。

  • 在调用 wait()之前,线程__必须要获得该对象的对象级别锁__,即__只能在同步方法或同步块中调用 wait()方法__。

    如果调用 wait()时,没有持有适当的锁,则抛出 IllegalMonitorStateException,它是 RuntimeException 的一个子类

  • notify

    (1)notify()也要在同步方法或同步块中调用,即在调用前,线程也必须要获得该对象的对象级别锁。如果调用 notify()时没有持有适当的锁,也会抛出 IllegalMonitorStateException。

    (2) notify 后,当前线程不会马上释放该对象锁,wait 所在的线程并不能马上获取该对象锁,它只是从等待池移动到了锁池,要等到程序退出 synchronized 代码块后,当前线程才会释放锁

    (3) 当第一个获得了该对象锁的wait线程运行完毕以后,它会释放掉该对象锁,此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他 wait 状态等待的线程由于没有得到该对象的通知,会继续阻塞在wait状态,直到这个对象发出一个 notify 或 notifyAll。

      获得锁的线程 <---竞争锁成功----锁池 <---被notify/notifyAll--- 等待池
           |                                                       |
           ------------------主动调用wait--------------------------->
    
  • 上面的关于notify()的说明也适用于notifyAll(),它们的区别就是notify只唤醒一个等待相同对象锁的线程,notifyAll唤醒所有等待相同对象锁的线程

猜你喜欢

转载自blog.csdn.net/captxb/article/details/87603304