關於多線程的面試題

題目:子線程循環10次,接着主線程循環100次,接着又回到子線程循環10次,接着又回到主線程又循環100次,如此循環50次。寫出程序。

一、思路:

這是一道考察多線程的題目。應題目的要求,子線程循環10次和主線程循環100次的中途不能被打斷,則須要在循環方法裏面加入互斥鎖。要連續有規律運行主線程和子線程,能夠考慮當線程執行完一個週期的循環後,讓線程休眠讓出線程運行權,或者使用wita()和notify()方法。java

二、答案之一:

public class TranditionThreadCommunication {
	public static void main(String[] args) {

		final Business business = new Business();

		// 子線程循環
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 1; i <= 50; i++) {
					try {
						business.sub(i);
					} catch (InterruptedException e) {
					}
				}
			}
		}).start();

		// 主線程循環
		for (int i = 1; i <= 50; i++) {
			try {
				business.mian(i);
			} catch (InterruptedException e) {
			}
		}

	}
}

/**
 * 業務類型(包含各色的同步鎖)
 */
class Business {
	// sub()方法是否該運行標識
	private boolean bShouldSub = true;

	/**
	 * 循環100次打印的方法sub()
	 * 
	 * @param i
	 * @throws InterruptedException
	 */
	public synchronized void sub(int i) throws InterruptedException {
		while (!bShouldSub) { // 當 bShouldSub 爲 false 時,則等待
			this.wait();
		}
		for (int j = 1; j <= 10; j++) {
			System.out.println("sub thread :   第" + i + "行, 第" + j + "列");
		}
		bShouldSub = false; // 執行for循環後,標誌sub()方法不可再執行
		this.notify(); // 喚醒線程
	}

	/**
	 * 循環100次打印的方法mian()
	 * 
	 * @param i
	 * @throws InterruptedException
	 */
	public synchronized void mian(int i) throws InterruptedException {
		while (bShouldSub) {
			this.wait();
		}
		for (int j = 1; j <= 100; j++) {
			System.out.println("main thread :   第" + i + "行, 第" + j + "列");
		}
		bShouldSub = true; // 執行for循環後,標誌sub()方法可再執行了
		this.notify(); // 喚醒線程
	}
}

三、經驗:

(1)要用到共同數據(包括同步鎖)或共同算法的若干個方法應該歸在同一個類身上,這種設計體現了高類聚和程序的健壯性。像上面的循環10次和循環100次的操做都須要用到鎖時,能夠將這兩個方法加上鎖(synchronized)並放到Business類中。算法

(2)上面答案中的多線程

while (bShouldSub) {
			this.wait();
		}

借鑑了javaAPI 中的wait()方法的寫法,主要是爲了防止線程之間可能出現的僞喚醒。app

java API 中的wait()方法的原文以下:ide

public final void wait() throws InterruptedException 在其餘線程調用此對象的 notify() 方法或 notifyAll() 方法前,致使當前線程等待。換句話說,此方法的行爲就好像它僅執行 wait(0) 調用同樣。 當前線程必須擁有此對象監視器。該線程發佈對此監視器的全部權並等待,直到其餘線程經過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。而後該線程將等到從新得到對監視器的全部權後才能繼續執行。this

對於某一個參數的版本,實現中斷和虛假喚醒是可能的,並且此方法應始終在循環中使用:線程

synchronized (obj) {
    while (<condition does not hold>)
        obj.wait();
     // Perform action appropriate to condition
}

此方法只應由做爲此對象監視器的全部者的線程來調用。有關線程可以成爲監視器全部者的方法的描述,請參閱 notify 方法。 拋出: IllegalMonitorStateException - 若是當前線程不是此對象監視器的全部者。 InterruptedException - 若是在當前線程等待通知以前或者正在等待通知時,任何線程中斷了當前線程。在拋出此異常時,當前線程的中斷狀態 被清除。設計

相關文章
相關標籤/搜索