Java線程交互的三個方法(四)

Java中除了使用synchronized 同步以外,經常還使用java.lang.Object提供的三個方法wait()、 notify()、 notifyAll()三個方法完成更高級和精確的交互操作。

Java線程涉及的三個方法:

wait(): 導致當前的正在運行的線程等待,直到其他線程調用此對象的 notify() 方法或notifyAll() 方法。

notify() :喚醒在此對象監視器上等待的單個線程。

notifyAll():喚醒在此對象監視器上等待的所有線程。

這三種方法是對線程直接操作,也必須保證“單操作性”,所以必須寫在synchronized 的範圍下。

其中,notify()和notifyAll()的用法是差不多的,一個喚醒的是單個線程,一個喚醒的是全部線程。

遵循以下的使用模型VIP

模型A,在一個線程中等待和相關操作,另一個線程中喚醒:
在一個線程中
synchronized (this ) {
    if (!condition) {// 當條件不滿足時,執行wait()方法
        wait();
    }
    // 當條件滿足時,執行相關操作
    doBThreadthing();
}

在另外一個線程中
synchronized (this ) {
    notify();
}

模型B,兩個線程都有等待,喚醒和相關操作,只是條件相反:
synchronized (this ) {
    if (condition) {// 當條件不滿足時,執行wait()方法
        wait();
    }
    // 當條件滿足時,執行相關操作
    doBThreadthing();
    notify();
}

模型B實現了,兩個線程完整的交互操作,著名的生產者和消費者模型就是使用了這個。

在生產者和消費者模型中,生產者和消費者是兩個獨立的線程,具有以下幾個交互規則:

1、生產者生成資源供消費者使用
2、生產者生產時,消費者等待
3、消費者消費時生產者等待
4、消費者使用完畢,喚醒生產者
5、生產者生產完畢,喚醒消費者

class MyProducer extends Thread {
	Storage storage;

	public MyProducer(Storage storage) {
		this.storage = storage;
	}

	@Override
	public void run() {
		storage.produce();
	}

}

class MyConsumer extends Thread {
	Storage storage;

	public MyConsumer(Storage storage) {
		this.storage = storage;
	}

	@Override
	public void run() {
		while (true) {
			storage.consume();
		}
	}

}

class Storage {
	//將生產者和消費者的方法寫到一個類當中,是爲了使兩個線程操作一個list對象,如果將list傳入每個線程當中,操作的不是一個list對象。
	List<String> mList = new ArrayList<String>();

	public void produce() {
		synchronized (this) {
			for (int i = 1; i < 5; i++) {
				if (mList.size() != 0) {
					try {
						System.out.println("生產者在等待");
						wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				for (int j = 0; j <= i; j++) {
					mList.add("蛋糕");
				}
				System.out.println("生產者生產了" + i + "塊蛋糕");
				notify();
			}
		}
	}

	public void consume() {
		synchronized (this) {
			if (mList.size() == 0) {
				try {
					System.out.println("消費者在等待");
					wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int i = 1 ; i < mList.size(); i++){
				System.out.println("消費者消費了第" + (i) + "塊蛋糕");
			}
			mList.clear();
			notify();
		}
	}
}

public class Module {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Storage storage = new Storage();
		MyProducer myProducer = new MyProducer(storage);
		MyConsumer myConsumer = new MyConsumer(storage);
		myConsumer.start();
		myProducer.start();
	}

}

運行結果:


Java線程是一塊難點,本人學的也不精,歡迎一起探討。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章