java语言中if语句的处理流程(Java中Object类的notify方法会导致死锁吗)

一、notify()和notifyAll()区别

Java提供了两个方法notify和notifyAll来唤醒在某些条件下等待的线程,你可以使用它们中的任何一个,notify() 是对notifyAll()的一个优化,它有很精确的应用场景,并且要求正确使用,不然可能导致死锁。以下为两者区别。

java语言中if语句的处理流程(Java中Object类的notify方法会导致死锁吗)(1)

图1 notify()方法源码

java语言中if语句的处理流程(Java中Object类的notify方法会导致死锁吗)(2)

图2 notifyAll()方法源码

1、如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁

2、notify和notifyAll之间的关键区别在于notify()只会唤醒等待池中的一个线程,进入锁池争夺资源;而notifyAll方法将唤醒对象的等待池中的所有线程,进入锁池。当你调用notify时,只有一个等待线程会被唤醒而且它不能保证哪个线程会被唤醒,这取决于线程调度器。如果你调用notifyAll方法,那么等待该锁的所有线程都会被唤醒,但是在执行剩余的代码之前,所有被唤醒的线程都将争夺对象锁。

3、notify可能会导致死锁,而notifyAll不会导致死锁。

二、为何notify为导致死锁

1、先解释两个概念。a、等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池,等待池中的线程不会去竞争该对象的锁。b、锁池:等待池中的线程,收到notify()或者notifyAll()方法通知的时候,会从等待池中移除,进入到锁池,锁池中的线程会竞争锁资源,只有获取了对象的锁,线程才能执行对象的 synchronized 代码,对象的锁每次只有一个线程可以获得,其他线程只能在锁池中等待,一旦发现对象锁有所释放,便会进入到下一个轮回的锁竞争

2、解释产生死锁的情况

有上述两个概念就可知,当出现这种情况,多个线程调用了锁对象的wait()方法,这些线程都会进入到等待池中,等待池中的线程不参与锁竞争。此时只调用一次notify()方法,那么只有一个线程会从等待池进入到锁池竞争资源,并且获得锁资源继续执行接下来的代码。执行完毕后,释放锁。但是由于其它线程都处于等待池中,不会去竞争争夺锁,大家都在等待池中等待通知,故而造成了死锁。除非再次调用notify()或者notifyAll()去触发通知,否则会一直等待下去。

三、代码演示notify可能产生死锁

1、执行wait方法,阻塞线程,负责释放当前持有的锁,代码如下:

package org.andy.effective.java.study; //调用wait方法,阻塞线程,释放当前持有的锁 public class RunnableWait implements Runnable { private Object obj; public RunnableWait(Object obj) { this.obj = obj; } @Override public void run() { System.out.println(Thread.currentThread().getName() "【run on RunnableWait】"); // 同步代码块 synchronized (obj) { System.out.println(Thread.currentThread().getName() "【obj to wait on RunnableWait】"); try { // 释放锁 obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() "【obj continue to run on RunnableWait】"); } } }

2、持有锁的代码块执行完毕,调用notify方法,释放锁,仅通知等待池中一个线程进入锁池竞争获取锁,代码如下:

3、持有锁的代码块执行完毕,调用notifyAll方法,释放锁,通知等待池中所有线程进入锁池竞争获取锁,代码如下:

package org.andy.effective.java.study; //持有锁的代码块执行完毕,调用notifyAll方法,释放锁,通知等待池中所有线程进入锁池竞争获取锁 public class RunnableNotifyAll implements Runnable { private Object obj; public RunnableNotifyAll(Object obj) { this.obj = obj; } @Override public void run() { System.out.println(Thread.currentThread().getName() "【run on RunnableNotifyAll】"); System.out.println("睡眠3秒..."); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } // 同步代码块 synchronized (obj) { System.out.println(Thread.currentThread().getName() "【notify obj on RunnableNotifyAll】"); // 通知所有等待线程 obj.notifyAll(); } } }

4、wait和notify配合产生死锁代码样例:

java语言中if语句的处理流程(Java中Object类的notify方法会导致死锁吗)(3)

图3 notify方法可能导致死锁样例

5、wait和notifyAll配合使用,不会导致死锁。

java语言中if语句的处理流程(Java中Object类的notify方法会导致死锁吗)(4)

图4 notifyAll方法不会产生死锁

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页