`
跑龙套_az
  • 浏览: 7174 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

notify与notifyAll的区别

阅读更多

         最近在多线程编程中用到了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();
	}
}

 

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics