wait()、wait(long timeout)、sleep(long timeout)

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()方法结束");
        }
    }
}
运行结果

wait()、wait(long timeout)、sleep(long timeout)

我们给两个线程都上了同一把锁对象,而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)方法结束");
        }
    }

运行结果:

wait()、wait(long timeout)、sleep(long timeout)

可以发现此时,在thread-0线程执行doWait()方法结束后,main线程开始执行doNotify()方法。证明sleep(long timeout)在等待的过程中,并没有释放锁对象,时间一到后,就重新进入了Runnable状态。

 

wait()、wait(long timeout)、sleep(long timeout)

上一篇:回收DHCP地址池中的IP地址


下一篇:题解 [ABC156E] Roaming