1. 程式人生 > 其它 >多執行緒使用wait和notify做生產者消費者模型導致執行緒全部假死

多執行緒使用wait和notify做生產者消費者模型導致執行緒全部假死

分析假死的原因:

首先我們每次只生產一個數據,然後消費者進行消費,

public class Value {
	public static String value = "";//這個值作為生產消費的容器
}

生產者端程式碼:

private String lock;

	public Producer (String lock) {
		super();
		this.lock = lock;

	}

	public void setValue() {
		try {
			synchronized (lock) {
				while (!"".equals(Value.value)) {
					System.out.println("生產者:"+Thread.currentThread().getName()+"等待");
					lock.wait();
				}
				System.out.println("生產者:"+Thread.currentThread().getName()+"開始工作了");
				String value = "Producer";
				System.out.println("set value :"+value);
				Value.value = value;
				lock.notify();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

消費者端

private String lock;

	public Consumer(String lock) {
		this.lock = lock;

	}

	public void getValue() {
		try {
			synchronized (lock) {
				if ("".equals(Value.value)) {
					System.out.println("消費者:"+Thread.currentThread().getName()+"等待");
					lock.wait();
				}
				System.out.println("消費者:"+Thread.currentThread().getName()+"開始消費了");
				System.out.println("get value :"+Value.value );
				Value.value = "";
				lock.notify();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
public class MyThread1 extends Thread {
	private Producer p;

	public MyThread1(Producer  p) {
		this.p = p;
	}
	
	@Override
	public void run() {
		while(true){
			p.setValue();//此執行緒不停的生產
		}
		
	}
package com.demo.thread;

public class MyThread2 extends Thread{
	private Consumer c;
	public MyThread2(Consumer c) {
		this.c = c;
	}
	
	@Override
	public void run() {
		while (true) {
			c.getValue();//此執行緒不聽的消費
			
		}
	}
}

測試:

String lock = new String("lock");
		Producer p = new Producer (lock);
		Consumer c = new Consumer (lock);
		MyThread1[] t1 = new MyThread1[2];
		
		MyThread2 [] t2 = new MyThread2[2];
		
		for(int i = 0 ;i<2;i++){
			t1[i] = new MyThread1(p);
			t1[i].setName("生產者:"+(i+1));
			t2[i] = new MyThread2(c);
			t2[i].setName("消費者:"+(i+1));
			t1[i].start();
			t2[i].start();
			
		}
		
		Thread.sleep(3000);
		Thread[] tArr = new Thread [Thread.currentThread().getThreadGroup().activeCount()];
		Thread.currentThread().getThreadGroup().enumerate(tArr);
		for(int i = 0 ;i<tArr.length;i++){
			System.out.println(tArr[i].getName()+"t"+tArr[i].getState());
		}

擷取控制檯程式碼部分程式碼: 分析:因為notify每次只喚醒一個執行緒,因此並不確定他喚醒的是哪一個執行緒,所以消費1喚醒的是消費者2,此時剛好沒有資料被生產,消費者2也進入等待,並喚醒生產者2,生產者2生產完資料之後進入wait同時喚醒執行緒,此時喚醒的是生產者1 ,因為資料不為空,因此兩生產者都進入等待狀態,此時四個執行緒全部wait,即假死狀態,結果如控制檯所示. 解決方式:這裡每次執行完畢之後應該喚醒所有執行緒即可.

生產者:生產者:2開始工作了
set value :Producer
消費者:消費者:1開始消費了
get value :Producer
消費者:消費者:1等待
生產者:生產者:2開始工作了
set value :Producer
生產者:生產者:2等待
生產者:生產者:1等待
消費者:消費者:2開始消費了
get value :Producer
消費者:消費者:2等待
生產者:生產者:2開始工作了
set value :Producer
生產者:生產者:2等待
生產者:生產者:1等待
消費者:消費者:1開始消費了
get value :Producer
消費者:消費者:1等待//消費者1等待,喚醒消費者2
消費者:消費者:2開始消費了
get value :
消費者:消費者:2等待//消費者2喚醒生產者2
生產者:生產者:2開始工作了
set value :Producer
生產者:生產者:2等待//從這裡開始,生產者2喚醒1,兩者最後都進入wait.
生產者:生產者:1等待
main	RUNNABLE
生產者:1	WAITING
消費者:1	WAITING
生產者:2	WAITING
消費者:2	WAITING