本文原地址:https://www.dyzhello.club/static/page/readArticle.html?id=15448
原创内容转载请注明
wait(),sleep() 的区别
- wait():Object类中定义的实例方法。在指定对象上调用wait方法会让当前线程进入等待状态(前提是当前线程持有该对象的monitor。ps:java中锁是对monitor的实现),此时当前线程会释放相应对象的monitor,这样一来其它线程便有机会获取这个对象的monitor了。当其它线程获取了这个对象的monitor并进行了所需操作时,便可以调用notify方法唤醒之前进入等待状态的线程。
- sleep():Thread类中的静态方法,作用是让当前线程进入休眠状态,以便让其他线程有机会执行。进入休眠状态的线程不会释放它所持有的锁。
-
在Java中,每个对象都有两个池,锁(monitor)池和等待池
锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(因为wait()方法必须出现在synchronized中,这样自然在执行wait()方法之前线程A就已经拥有了该对象的锁),同时线程A就进入到了该对象的等待池中。如果另外的一个线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,准备争夺锁的拥有权。如果另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池.
深入理解:
如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
需要注意的是:
正是因为每个实例对象拥有一个monitor对象所以在object里默认的友wait()、notify()、notifyAll()方法
wait必须在synchronized内部调用
实例:
package com.example.demo;
public class SleepAndWait {
public static void main(String[] args) throws InterruptedException {
// 线程一开始执行五秒后执行线程二
new Thread1().start();
Thread.sleep(5000);
new Thread2().start();
}
}
class Thread1 extends Thread {
@Override
public void run() {
// 获取SleepAndWait类对象锁
synchronized (SleepAndWait.class) {
System.out.println("thread1开始执行");
try {
// 释放线程锁并进入阻塞状态,需要notify方法进行唤醒,
// 如果没有收到该方法唤醒即使抢占的对象锁处于未被锁定状态仍然不会醒来
SleepAndWait.class.wait(); // 让出cpu(即该对象的监听者不监听该线程),同时释放对象锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thread1完全退出");
}
}
class Thread2 extends Thread {
@Override
public void run() {
synchronized (SleepAndWait.class) {
System.out.println("thread2开始执行");
// 唤醒其他线程
SleepAndWait.class.notifyAll();// 让出cpu,但不会释放锁
System.out.println("已通知其他等待对象");
try {
Thread.sleep(5000); // 休眠不会让出对象锁
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread2完全退出");
}
}
}