閱讀707 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Java多線程的例子及synchronized關鍵字鎖定對象的用法

該例子所應用場景:一個線程負責生產,多個線程(該例為3個)負責消費;生產者不斷的往堆棧中加入數據,消費者不斷的從堆棧中取數據。

代碼如下:

package com.xs.mail.thread;

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

class Widget {
}

class WidgetMaker extends Thread {
	List<Widget> finishedWidgets = new ArrayList<Widget>();

	public void run() {
		try {
			while (true) {
				//每1秒鍾生產一個Widget
				Thread.sleep(1000);// act busy
				Widget w1 = new Widget();
				// 也就是說需要5秒鍾才能新產生一個Widget,這決定了一定要用notify而不是notifyAll
				// 因為上麵兩行代碼不是同步的,如果用notifyAll則所有線程都企圖衝出wait狀態
				// 第一個線程得到了鎖,並取走了Widget(這個過程的時間小於5秒,新的Widget還沒有生成)
				// 並且解開了鎖,然後第二個線程獲得鎖(因為用了notifyAll其他線程不再等待notify語句
				// ,而是等待finishedWidgets上的鎖,一旦鎖放開了,他們就會競爭運行),運行
				// finishedWidgets.remove(0),但是由於finishedWidgets現在還是空的,
				// 於是產生異常
				// ***********這就是為什麼下麵的那一句不能用notifyAll而是要用notify

				synchronized (finishedWidgets) {
					finishedWidgets.add(w1);
					finishedWidgets.notify(); // 這裏隻能是notify而不能是notifyAll
				}
			}
		} catch (InterruptedException e) {
		}
	}

	public Widget waitForWidget() {
		synchronized (finishedWidgets) {
			if (finishedWidgets.size() == 0) {
				try {
					System.out.println("暫停線程:" + Thread.currentThread().getName());
					finishedWidgets.wait();
				} catch (InterruptedException e) {
				}
			}
			return finishedWidgets.remove(0);
		}
	}
}

public class WidgetUser extends Thread {
	private WidgetMaker maker;

	public WidgetUser(String name, WidgetMaker maker) {
		super(name);
		this.maker = maker;
	}

	public void run() {
		while (true) {
			Widget w = maker.waitForWidget();
			System.out.println(getName() + " got a widget");
		}
	}

	public static void main(String[] args) {
		WidgetMaker maker = new WidgetMaker();
		maker.start();
		new WidgetUser("Tom", maker).start();
		new WidgetUser("Jack", maker).start();
		new WidgetUser("Marry", maker).start();
	}
}


最後更新:2017-04-02 22:15:57

  上一篇:go 12.9 訓練 E - Ternary Password
  下一篇:go Chrome 開始允許用戶自己監控擴展的活動