應用場景
需要開啓多個線程,之後每個線程爭搶鎖,獲取倒計時秒數權限,從而輪流打印倒計時
代碼實現
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();這行代碼。