欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

notify与notifyAll的区别

程序员文章站 2022-07-12 19:33:12
...

         最近在多线程编程中用到了wait(),随之即面临notify与notifyAll的选择、本人代码中使用两者皆可,查看两者的定义后、发现两者的选择还是很讲究的。

 

        所有处于wait状态的线程,需要使用notify或者notifyAll才能被唤醒、重新被唤醒进入锁的争夺队列。notify即随机唤醒等待中的一条线程;notifyAll即唤醒全部处于等待中的线程。

 

        两者的使用上都存在缺陷,使用notify时、容易导致死锁,而使用notifyAll时容易导致资源竞争使用的异常。所以两者的使用得根据实际情况选择、并没有说普遍的说法。下面分别提供两者使用出错的例子供参考:

 

        使用notify出现死锁:

public class NotifyTest {
	public static void main(String[] args) {
		final OutTurn ot = new OutTurn();
		
		for(int i=0; i<30; i++) {
			new Thread(new Runnable() {
				public void run() {
					ot.isSub();
				}
			}).start();		
		}
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		for(int i=0; i<30; i++) {
			new Thread(new Runnable() {
				public void run() {
					ot.isNotSub();
				}
			}).start();	
		}
		System.out.println("Thread cread complate...");
	}
}

 

public class OutTurn {
	
	private boolean isSub = true;
	private int count = 0;
	private int threadCount = 0;
		
	public synchronized void isSub() {
		System.out.println(threadCount++);
		try {
			while(!isSub) {
				System.out.println(Thread.currentThread().getName() + "- sub --- wait --" + count);
				this.wait();
			}
			System.out.println(Thread.currentThread().getName() + "- sub --- " + count);
			isSub = false;
			this.notify();\\采用notifyAll即不会死锁
		} catch (Exception e) {
			e.printStackTrace();
		}
		count++;
	}
		
	public synchronized void isNotSub() {
		System.out.println(threadCount++);
		try {
			while(isSub) {
				System.out.println(Thread.currentThread().getName() + "- Not --- wait ---" + count);
				this.wait();
			}
			System.out.println(Thread.currentThread().getName() + "- Not --- " + count);
			isSub = true;
			this.notify();
		} catch (Exception e) {
			e.printStackTrace();
		}
		count++;			
	}
}

 

         使用notifyAll出现异常:

package notify;

import java.util.ArrayList;
import java.util.List;

public class IntegerMaker implements Runnable {
	List<Integer> container = new ArrayList<Integer>();
	Integer i = 1;
	@Override
	public void run() {		
		try {
			while(true) {
				Thread.sleep(5000);
				Integer a = i++;
				synchronized(container) {
					container.add(a);
					container.notify();//notifyAll将出现异常
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}		
	}
	
	public Integer waitFor() {
		synchronized(container) {
			System.out.println("size");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			if(container.size() == 0) {
				try {
					container.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println("size: " + container.size());
			return container.remove(0);
		}
	}
	
}

 

package notify;

public class IntegerUser implements Runnable {
	private IntegerMaker maker;
	private String name;
	
	public IntegerUser(IntegerMaker maker, String name) {
		this.maker = maker;
		this.name = name;
	}
	
	public void run() {
		Integer a = maker.waitFor();
		System.out.println(this.name + ":get:" + a);
	}
	
	public static void main(String[] args) {
		IntegerMaker temp = new IntegerMaker();
		Thread maker = new Thread(temp); 
		maker.start();
		new Thread(new IntegerUser(temp, "xiaoge1"), "xiaoge1").start();
		new Thread(new IntegerUser(temp, "xiaoge2"), "xiaoge2").start();
		new Thread(new IntegerUser(temp, "xiaoge3"), "xiaoge3").start();
	}
}

 

          因此两者的选择必须根据实际情况做具体的分析、然后决定应该唤醒一个还是全部。

相关标签: notify notifyAll