wait() ==>进入无限等待状态 肯定释放锁对象
wait(long timeout)==>进入计时等待状态 肯定释放锁对象
sleep(long timeout)==>进入计时等待状态 无需释放锁对象
原理:
如果一个线程调用了wait()方法就进入了无限等待状态,那么这时肯定要释放锁对象,不然这个锁对象就浪费了。
特别注意的是就算调用了wait(long timeout)进入了计时等待,还是会释放锁对象的。
而如果是调用了sleep(long timeout),那么其是进入计时等待状态,时间一到,那么就会自动唤醒,这时就不必
释放锁对象。自动唤醒后,就可以直接进入Runnable(可运行)状态。
写一个demo验证,让wait()和notify()使用同一个锁对象,看wait()是否会释放锁对象。
让主线程执行notify()方法,而新建一个线程执行wait()方法,且让新线程(命名为thread-0)优先于主线程执行。
package prac.Thread.sleepAndWait; // 测试sleep(int m)和wait(int m) 在执行时,是否会释放锁对象 public class Differences { // 新建一个锁对象 private static final Object obj = new Object(); public static void main(String[] args) throws InterruptedException { // main线程和新线程用的是同一个锁对象 // 开启新线程,来执行wait方法 new Thread(){ @Override public void run() { try { doWait(); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); // 调用sleep方法,让主线程慢执行于上面的新线程 Thread.sleep(1000); // main线程执行notify方法 doNotify(); } /** wait() ==>进入无限等待状态 肯定释放锁对象 wait(long timeout)==>进入计时等待状态 肯定释放锁对象 sleep(long timeout)==>进入计时等待状态 无需释放锁对象 原理: 如果一个线程调用了wait()方法就进入了无限等待状态,那么这时肯定要释放锁对象,不然这个锁对象就浪费了, 特别注意的是wait(long timeout),虽然进入了计时等待,但是它也是会释放锁对象的。 而如果是调用了sleep(1000),那么其是进入计时等待状态,时间一到,那么就会自动唤醒,这时就不必 释放锁对象。自动唤醒后,就可以直接进入Runnable(可运行)状态。 */ private static void doWait() throws InterruptedException{ synchronized(obj){ System.out.println("开始调用wait()方法"); obj.wait(); System.out.println("调用wait()方法结束"); } } // 执行notify方法 private static void doNotify(){ synchronized(obj){ System.out.println("开始调用notify()方法"); obj.notify(); System.out.println("调用notify()方法结束"); } } }
运行结果:
我们给两个线程都上了同一把锁对象,而thread-0线程先获取了锁对象,故第一行打印了“开始调用wait方法”,而第二行和第三行打印的是main线程调用的方法,可以说明thread-0线程执行到wait()方法时,就进入了无限等待状态,且释放了锁对象,否则main线程不可能有CPU的执行权,而当main线程执行了notify()唤醒操作后,thread-0线程就被唤醒了,在main线程执行完线程任务并释放锁对象后,thread-0线程重新获得锁对象,重新进入Runnable状态,继续执行未执行的代码。
代码证明sleep(long timeout)是没有释放锁对象的
对上面的代码进行修改如下:
private static void doWait() throws InterruptedException{ synchronized(obj){ System.out.println("开始调用sleep(100)方法"); Thread.sleep(100); System.out.println("调用sleep(100)方法结束"); } }
运行结果:
可以发现此时,在thread-0线程执行doWait()方法结束后,main线程开始执行doNotify()方法。证明sleep(long timeout)在等待的过程中,并没有释放锁对象,时间一到后,就重新进入了Runnable状态。