关于notify与notifyAll的区别及为什么notify会导致死锁

概念

notify与notifyAll及wait是属于Object的方法,注意区别于sleep、yield,这些是Thread类的方法

概念:锁池和等待池
锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中

再来说notify和notifyAll的区别
如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。

 

notify()可能会导致死锁,而notifyAll()则不会

为什么?

notify()只唤醒一个正在等待的线程,当该线程执行完以后施放该对象的锁,而没有再次执行notify()方法,
则其它正在等待的线程
则一直处于等待状态,不会被唤醒而进入该对象的锁的竞争池,就会发生死锁

JVM多个线程间的通信是通过 线程的锁、条件语句、以及wait()、notify()/notifyAll组成

public class OutTurn {
	private boolean isSub = true;
	private int count = 0;

	public synchronized void sub() {
		try {
			while (!isSub) {
				this.wait();
			}
			System.out.println("sub  ---- " + count);
			isSub = false;
			this.notify();
		} catch (Exception e) {
			e.printStackTrace();
		}
		count++;

	}

	public synchronized void main() {
		try {
			while (isSub) {
				this.wait();
			}
			System.out.println("main (((((((((((( " + count);
			isSub = true;
			this.notify();
		} catch (Exception e) {
			e.printStackTrace();
		}
		count++;
	}
}
public class LockDemo {
	public static void main(String[] args) {
		// System.out.println("lock");

		final OutTurn ot = new OutTurn();

		for (int j = 0; j < 100; j++) {

			new Thread(new Runnable() {

				public void run() {
					// try {
					// Thread.sleep(10);
					// } catch (InterruptedException e) {
					// e.printStackTrace();
					// }
					for (int i = 0; i < 5; i++) {
						ot.sub();
					}
				}
			}).start();

			new Thread(new Runnable() {

				public void run() {
					// try {
					// Thread.sleep(10);
					// } catch (InterruptedException e) {
					// e.printStackTrace();
					// }
					for (int i = 0; i < 5; i++) {
						ot.main();
					}
				}
			}).start();
		}

	}
}

执行结果:
notify()方法每次会卡住不继续执行,每次卡住的位置也不一样

修改为notifyAll后,可以执行完

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值