java多線程倒計時輪流輸出synchronized Integer鎖問題

java多線程倒計時輪流輸出

應用場景

需要開啓多個線程,之後每個線程爭搶鎖,獲取倒計時秒數權限,從而輪流打印倒計時

代碼實現

public class ThreadSyncCountDown {
	Integer seconds = 20;
	Integer lock = new Integer(1);

	public static void main(String[] args) {
		// 開啓3個線程,同步輸出倒計時20s,
		ThreadSyncCountDown t = new ThreadSyncCountDown();
		t.threadMethod(3);
	}

	// count 線程數量,seconds倒計時秒數
	public void threadMethod(int count) {

		// 遍歷線程
		for (int i = 0; i < count; i++) {

			// lambda 表達式實現函數式接口
			new Thread(() -> {

				while (seconds >= 0) {
					countDown();

				}

			}).start();

		}

	}

	public void countDown() {
		synchronized (lock) {
			if (seconds < 0)
				return;
			// 格式化時間輸出
			SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			System.out.println(String.format("線程:%s,倒計時:%d,當前時間:%s", Thread.currentThread().getId(), seconds--, sf.format(new Date())));

			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			lock.notifyAll();

		}
		System.out.println();
	}

}

結果展示

在這裏插入圖片描述

注意細節

上述代碼中原本synchronized(){} 代碼塊參數是需要倒計時的變量seconds,但是由於java裝箱拆箱機制seconds–實際上是seconds = new Integer(seconds–),由於鎖對象改變了,因此會報錯如下:java.lang.IllegalMonitorStateException
在這裏插入圖片描述
所以針對於需要上鎖的代碼塊,可以通過新定義一個不會改變的Integer lock = new Integer(1) 對象,或者直接用Object lock = new Object();這樣就可以對代碼塊成功上鎖,並且此處爲了方便看到lock.notifyAll() 的效果。在上鎖代碼塊執行完成後,通過降低當前線程的爭搶鎖能力,加了System.out.println();這行代碼。

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