注意事项一: 当前线程调用共享对象的wait()方法时,当前线程只会释放当前共享对象的锁,当前线程持有的其他共享对象的监视器锁并不会被释放。

下面举个栗子:

    private static volatile Object resourceA = new Object();
    private static volatile Object resourceB = new Object();

    public static class ResourceA implements Runnable {

        @Override
        public void run() {

            try{

                // 获取resourceA的共享资源监视器锁
                synchronized (resourceA) {
                    System.out.println("获取线程A中resourceA的锁");
                    // 获取resourceB的共享资源的监视器锁
                    synchronized (resourceB) {
                        System.out.println("获取线程A中resourceB的锁");

                        // 线程A阻塞,并释放获取到的resourceA的锁
                        System.out.println("将线程A挂起,并释放resourceA的锁");
                        resourceA.wait();
                    }
                }
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static class ResourceB implements Runnable {

        @Override
        public void run() {

            try{
            	// 休眠1s
                Thread.sleep(1000);

                // 获取resourceA的共享资源监视器锁
                synchronized (resourceA) {
                    System.out.println("获取线程B中resourceA的锁");

                    System.out.println("获取线程B中resourceB的锁");

                    // 获取resourceB的共享资源的监视器锁
                    synchronized (resourceB) {
                        System.out.println("获取线程B中resourceB的锁...");

                        // 线程B阻塞,并释放获取到的resourceA的锁
                        System.out.println("获取线程B中resourceB的锁...");
                        resourceA.wait();
                    }
                }
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {

       Thread a = new Thread(new ResourceA());
       Thread b = new Thread(new ResourceB());

       a.start();
       b.start();

       a.join();
       b.join();
    }

运行结果:
Java多线程wait()方法注意事项
将线程A中的resourceB锁注释掉

  // 获取resourceA的共享资源监视器锁
  synchronized (resourceA) {
       System.out.println("获取线程A中resourceA的锁");
       // 获取resourceB的共享资源的监视器锁
       //synchronized (resourceB) {
           System.out.println("获取线程A中resourceB的锁");

           // 线程A阻塞,并释放获取到的resourceA的锁
           System.out.println("将线程A挂起,并释放resourceA的锁");
           resourceA.wait();
       //}
   }

运行结果如下:
Java多线程wait()方法注意事项

在上述代码中,在main函数中分别启动了A线程和B线程,为了让线程A先获取到资源,这里让线程B休眠了1s,线程A先获取到共享变量resourceA和共享变量resourceB的锁,然后resourceA的wait()方法挂起了自己,并释放了resourceA的锁。

线程B休眠结束后,肯定先尝试获取resourceA上的锁,如果当时线程A还没有调用wait()方法释放该锁,则线程B会被阻塞,当线程A释放了resourceA上的锁后,线程B就会获取到resourceA上的锁,然后尝试获取resourceB上的锁。由于线程A调用的是resourceA上的wait()方法,所以并没有将resourceB上的锁给释放掉,当线程B尝试获取resourceB上的锁时就会被阻塞。


总结: 当前线程调用共享变量对象的wait()方法时,当前线程只会释放当前共享对象的锁,当前线程持有的其他共享对象的监视器锁并不会被释放。

注意事项二: 当一个线程调用共享对象的wait()方法被挂起后,如果其他线程中断了该线程,则该线程会抛出InterruptedException异常并返回。

在举个栗子:

 private static Object obj = new Object();

    public static class ResourceA implements Runnable {

        @Override
        public void run() {
            try{
                System.out.println("---开始---");
                // 阻塞当前线程
                synchronized (obj) {
                    obj.wait();
                }
                System.out.println("---结束---");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new ResourceA());

        thread.start();

        Thread.sleep(1000);

        System.out.println("--interrupt开始--");
        thread.interrupt();
        System.out.println("--interrupt结束--");
    }

运行结果如下:
Java多线程wait()方法注意事项

thread调用共享对象obj的wait()方法后挂起了自己,然后在主线程休眠1s后中断了thread线程,中断后thread会在obj.wait处抛出java.lang.InterruptedException异常而返回并终止。

相关文章: