sleep和wait

由一道关于sleep()和wait()方法的题目展开

关于sleep()wait(),以下描述错误的一项是:

- A sleep是线程类(Thread)的方法,waitObject类的方法;

- B sleep不释放对象锁,wait放弃对象锁

- C sleep暂停线程、但监控状态仍然保持,结束后会自动恢复

- D wait后进入等待锁定池,只有针对此对象发出notify方法后获得对象锁进入运行状态

   

关于A

   

sleep是Thread类中的方法,而wait、notify、notifyAll都是Object类中的方法。

sleep、wait的使用范围:

sleep是Thread类中的静态方法。因此无论是在a线程中调用b的sleep方法,还是在b线程中调用a的sleep方法,谁调用谁就sleep。也因此,sleep可以在任何地方使用。

wait、notify、notifyAll就很惨了,只能在同步控制方法或同步控制块中使用。

   

关于B、C

   

经过一个英语渣渣copy部分源代码并且翻译之后得到的内容是

sleep():

使当前执行线程休眠(暂时停止执行),以指定毫秒数加上指定的纳秒数,以系统定时器和调度器的精度和准确性为准。线程不会丢失任何监视器(monitor)的所有权

因为sleep()并没释放锁,所以仍旧处在同步状态,监控仍旧存在,睡眠时间结束后自动恢复运行。

wait():

当前线程必须拥有该对象的监视器(monitor)。线程释放此监视器(monitor)的所有权,并等待,直到另一个线程通过调用{@code notify}方法或{@code notifyAll}方法通知等待此对象的监视器的线程醒来。然后线程等待,直到它能够重新获得监视器的所有权并恢复执行。 

 wait()释放掉锁,所以不再处于同步状态。

注:对象锁就是常说的同步锁——synchronized。监视器(monitor)或者说其所有权我也理解为对象锁,毕竟锁住以后就又拥有的权利了,以上翻译如若有错,百度的锅。

   

关于D

   

这里就需要提及两个概念,Java中每个对象都有两个池:锁池、等待池。

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

等待池:假设线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(原因是wait()必须出现在synchronized锁里面,自然执行wait()方法前就拥有了这个对象的锁,源代码翻译中提到wait()释放监视器所有权,即释放锁)(wait的是这个对象对应的现在正在充当锁的同步部分),同时线程A进入该对象的等待池中。如果另一个线程调用了该相同对象的notifyAll()方法,那么处于该对象中的所有线程会进入该对象的锁池中,准备争夺锁的拥有权。如果另一个线程调用了该相同对象的notify()方法,那么仅仅只有一个处于该对象的等待池中的线程(随机的某个)进入锁池,准备得到锁的拥有权。

   

简单理解:

如果线程调用了对象的wait()方法,那么线程就处于该对象的等待池中,等待池中的线程不会去争夺锁的拥有权。

当线程调用了该对象的notify()方法或者notifyAll()方法,被唤醒的线程进入锁池,准备争夺锁的拥有权。假如某个线程没有争夺到锁,它仍旧停留在锁池中等待下一次的争夺,只有再次调用wait()方法才会进入等待池中。

   

以上线程拿到锁要干嘛?进入就绪状态,等待CPU时间片开始运行。

   

完整代码演示:

 

package test;

public class MultiThread {

       private static class Thread1 implements Runnable {

             @Override

             public void run() {

                    // 由于 Thread1和下面Thread2内部run方法要用同一对象作为监视器,如果用thisThread1Threa2this不是同一对象

                    // 所以用MultiThread.class这个字节码对象,当前虚拟机里引用这个变量时指向的都是同一个对象

                    synchronized (MultiThread.class) {

                           System.out.println("thread1 创建...");

                           System.out.println("thread1 就绪中");

                           try {

                                 // 释放锁有两种方式:(1)程序自然离开监视器的范围,即离开synchronized关键字管辖的代码范围

                                 // (2)synchronized关键字管辖的代码内部调用监视器对象的wait()方法。这里使用wait方法

                                 MultiThread.class.wait();

                           } catch (InterruptedException e) {

                                 e.printStackTrace();

                           }

                           System.out.println("thread1 正在运行 ...");

                           System.out.println("thread1 结束!");

                    }

             }

       }

       private static class Thread2 implements Runnable {

             @Override

             public void run() {

                    // notify方法并不释放锁,即使thread2调用了下面的sleep方法休息10ms,但thread1仍然不会执行

                    // 因为thread2没有释放锁,所以Thread1得不到锁而无法执行

                    synchronized (MultiThread.class) {

                           System.out.println("thread2 创建...");

                           System.out.println("thread2 此刻唤醒其他wait线程notify  other thread can release wait status ...");

                           MultiThread.class.notify();

                           try {

                                 System.out.println("thread2 睡了...");

                                 Thread.sleep(2000);

                           } catch (InterruptedException e) {

                                 e.printStackTrace();

                           }

                           System.out.println("thread2 正在运行...");

                           System.out.println("thread2 结束!");

                    }

             }

       }

       public void demo() {

             for (int i = 0; i < 5; i++) {

                    try {

                           Thread.sleep(2000);

                    } catch (InterruptedException e) {

                           // TODO Auto-generated catch block

                           e.printStackTrace();

                    }

                    System.out.println("" + i + "次输出");

             }

       }

       public static void main(String[] args) {

             new Thread(new Thread1()).start();

             try {

                    Thread.sleep(10);

             } catch (InterruptedException e) {

                    e.printStackTrace();

             }

             new Thread(new Thread2()).start();

             new MultiThread().demo();

       }

}package test;

public class MultiThread {

       private static class Thread1 implements Runnable {

             @Override

             public void run() {

                    // 由于 Thread1和下面Thread2内部run方法要用同一对象作为监视器,如果用thisThread1Threa2this不是同一对象

                    // 所以用MultiThread.class这个字节码对象,当前虚拟机里引用这个变量时指向的都是同一个对象

                    synchronized (MultiThread.class) {

                           System.out.println("thread1 创建...");

                           System.out.println("thread1 就绪中");

                           try {

                                 // 释放锁有两种方式:(1)程序自然离开监视器的范围,即离开synchronized关键字管辖的代码范围

                                 // (2)synchronized关键字管辖的代码内部调用监视器对象的wait()方法。这里使用wait方法

                                 MultiThread.class.wait();

                           } catch (InterruptedException e) {

                                 e.printStackTrace();

                           }

                           System.out.println("thread1 正在运行 ...");

                           System.out.println("thread1 结束!");

                    }

             }

       }

       private static class Thread2 implements Runnable {

             @Override

             public void run() {

                    // notify方法并不释放锁,即使thread2调用了下面的sleep方法休息10ms,但thread1仍然不会执行

                    // 因为thread2没有释放锁,所以Thread1得不到锁而无法执行

                    synchronized (MultiThread.class) {

                           System.out.println("thread2 创建...");

                           System.out.println("thread2 此刻唤醒其他wait线程notify  other thread can release wait status ...");

                           MultiThread.class.notify();

                           try {

                                 System.out.println("thread2 睡了...");

                                 Thread.sleep(2000);

                           } catch (InterruptedException e) {

                                 e.printStackTrace();

                           }

                           System.out.println("thread2 正在运行...");

                           System.out.println("thread2 结束!");

                    }

             }

       }

       public void demo() {

             for (int i = 0; i < 5; i++) {

                    try {

                           Thread.sleep(2000);

                    } catch (InterruptedException e) {

                           // TODO Auto-generated catch block

                           e.printStackTrace();

                    }

                    System.out.println("" + i + "次输出");

             }

       }

       public static void main(String[] args) {

             new Thread(new Thread1()).start();

             try {

                    Thread.sleep(10);

             } catch (InterruptedException e) {

                    e.printStackTrace();

             }

             new Thread(new Thread2()).start();

             new MultiThread().demo();

       }

}

 

 

posted @ 2020-03-23 16:43  BeeeenWei  阅读(568)  评论(0)    收藏  举报