1. 程式人生 > >java多執行緒之生產者消費者經典問題

java多執行緒之生產者消費者經典問題

看過 http://blog.csdn.net/thinkpadshi/article/details/8163751     下面的評論說:    感覺你的程式碼有問題啊,兩個run()方法裡面的列印語句的執行先後問題,假設開始在消費時index==0;這時wait()了,生產者便搶到鎖,index+1;同時叫醒消費者,這個時候要是消費者先於生產者的列印了一條消費了0個,之後再列印生產了0個怎麼辦??!,我執行後也發現這樣的問題,如果把100毫秒改為10毫秒,會有更多這樣的情況產生.

於是自己改了下博主的程式碼:

package deadLockThread;

public class SX {
	public static void main(String[] args) {
		ProductList pl = new ProductList();
		Factory f = new Factory(pl);
		Consumer c = new Consumer(pl);

		Thread t1 = new Thread(f);
		Thread t2 = new Thread(c);

		t1.start();
		t2.start();

	}
}

class Product {
	private int id;

	Product(int id) {
		this.id = id;
	}

	@Override
	public String toString() {
		return "Product [id=" + id + "]";
	}

}

class ProductList {
	int index = 0;
	private Product[] p = new Product[6];

	public synchronized void push(Product pr) {

		while (index == p.length) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.notify();
		p[index] = pr;
		<span style="color:#ff0000;">System.out.println("生產了" + p[index]);</span>
		index++;

	}

	public synchronized Product pop() {

		while (index == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.notify();
		index--;
		<span style="color:#ff0000;">System.out.println("消費了" + p[index]);</span>
		return p[index];

	}
}

class Factory implements Runnable {

	private ProductList pl = null;

	Factory(ProductList pl) {
		this.pl = pl;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 0; i < 20; i++) {
			Product p = new Product(i);
			pl.push(p);
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}
}

class Consumer implements Runnable {
	private ProductList pl = null;

	Consumer(ProductList pl) {
		this.pl = pl;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 0; i < 20; i++) {
			Product p = pl.pop();
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}
}
我就只是改動了  輸出的位置 這是由於System.out.println()函式不是立刻就列印的,它要呼叫其他的函式來完成輸出,所以System.out.println("生產了" + p[index]);  還有 System.out.println("消費了" + p[index]);具體的列印時間就不確定了.   但是如果把輸出列印放在同步程式碼塊裡面,就不會有這樣的問題.因為會完成列印之後才會執行下一步.