場景
程序裏面使用了synchronized
關鍵字,IntelliJ IDEA
右邊出現了黃色條,移動到上面,提示如下:
環境
軟件 | 版本 |
---|---|
JDK | 1.8 |
IntelliJ IDEA | 2019.1 |
原因
從提示來看,就是說,如果變量的引用發生了改變,就會導致synchronized
失效,然後其他線程就會進入原本沒有結束的synchronized
代碼塊。所以要使用final
來修飾變量,使引用不發生改變。
嘗試
接下來讓我們來驗證一下,是否真的如提示所說。
錯誤範例
我寫了以下代碼,請各位讀者看:
public class Test1 implements Runnable{
private Byte[] flag = new Byte[1];
@Override
public void run() {
synchronized (flag){
System.out.println(new Date()+" 開始休眠"+Thread.currentThread().getName());
flag = new Byte[11];
try {
Thread.sleep(10000);
System.out.println(new Date()+" 結束休眠"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Test1 test = new Test1();
new Thread(test).start();
Thread.sleep(100);
new Thread(test).start();
}
}
如果synchronized
關鍵字有生效的話,就會導致前後兩個線程會間隔10秒打印日誌。結果如下:
Fri Apr 10 22:03:43 CST 2020 開始休眠Thread-0
Fri Apr 10 22:03:43 CST 2020 開始休眠Thread-1
Fri Apr 10 22:03:53 CST 2020 結束休眠Thread-0
Fri Apr 10 22:03:53 CST 2020 結束休眠Thread-1
從結果可以看到,中間兩個線程基本沒有間隔就開始了。和我們的預期是存在差異的。那是什麼原因導致了變量的引用發生了改變嗎?就是代碼裏面的那行重新賦值的語句:
flag = new byte[11];
所以,也正如提示所說的,就是因爲變量的引用發生了改變,所以導致了synchronized
關鍵字沒有生效。接下來就讓我們開始正確的嘗試階段。
正確範例
我對錯誤範例
裏面的代碼進行優化,在這裏主要按照提示所說,加上final
來使得對象不必改變,各位讀者跟隨我的思路來。
public class Test1 implements Runnable{
private final Byte[] flag = new Byte[1];
@Override
public void run() {
synchronized (flag){
System.out.println(new Date()+" 開始休眠"+Thread.currentThread().getName());
flag[0] = 11;
// 因爲變量設置爲了final,沒有辦法進行修改。故註釋掉。
//flag = new Byte[11];
try {
Thread.sleep(10000);
System.out.println(new Date()+" 結束休眠"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Test1 test = new Test1();
new Thread(test).start();
Thread.sleep(100);
new Thread(test).start();
}
}
結果如下:
Sun Apr 12 00:25:33 CST 2020 開始休眠Thread-0
Sun Apr 12 00:25:43 CST 2020 結束休眠Thread-0
Sun Apr 12 00:25:43 CST 2020 開始休眠Thread-1
Sun Apr 12 00:25:53 CST 2020 結束休眠Thread-1
從結果來看,這個時候的synchronized
是已經生效了。因爲加了final
,導致變量無法被改變引用。
總結
併發情況下面,一個變量如果是打算作爲鎖,就得考慮是否會被更新引用的情況。所以,併發情況下,還是要多思考,才能寫出質量上乘的代碼。
隨緣求贊
如果我的文章對大家產生了幫忙,可以在文章底部點個贊或者收藏;
如果有好的討論,可以留言;
如果想繼續查看我以後的文章,可以左上角點擊關注