synchronized用于給方法或者塊加鎖用的,只有獲得該對象或者塊的鎖的對象才能夠執行里面的代碼,否則將阻塞在那里,等待該鎖被釋放,然后獲得該鎖繼續執行。比如下面模擬售票的代碼:
/*** 模擬售車票* * @author Administrator**/public class SynchronizedDemo { public static void main(String[] args) { Runnable runnable = new Runnable() { int count = 10; public void run() { while (true) { if (count <= 0) { break; } else { count--; //標記1 System.out.PRintln(Thread.currentThread().getName() + ":還剩余" + count + "張車票"); try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } } } } }; Thread t1 = new Thread(runnable); Thread t2 = new Thread(runnable); t1.start(); t2.start(); }}運行結果:
Thread-0:還剩余9張車票Thread-1:還剩余8張車票Thread-1:還剩余6張車票Thread-0:還剩余6張車票Thread-0:還剩余4張車票Thread-1:還剩余4張車票Thread-1:還剩余3張車票Thread-0:還剩余3張車票Thread-1:還剩余2張車票Thread-0:還剩余1張車票Thread-0:還剩余0張車票
假如當前count=8,當t1運行完標記1(代碼中紅色的標記)的時候count=7,恰巧該線程的時間片用完了。這時候t2開始運行,當t2運行完標記1的時候count=6,接著輸出count的值,會輸出還剩余6張,此時t2的時間片用完后,t1開始接著標記1后面執行,輸出count的值,會輸出還剩余6張,這才輸出了上述中的結果。
解決辦法:
如果加入了synchronized代碼塊的話即可解決上述問題,核心代碼如下
synchronized (this) {//標記2 count--; System.out.println(Thread.currentThread().getName() + ":還剩余" + count + "張車票");
}
其中this表示的是要鎖住對象的地址。
運行結果:
Thread-0:還剩余9張車票Thread-1:還剩余8張車票Thread-0:還剩余7張車票Thread-1:還剩余6張車票Thread-1:還剩余5張車票Thread-0:還剩余4張車票Thread-1:還剩余3張車票Thread-0:還剩余2張車票Thread-0:還剩余1張車票Thread-1:還剩余0張車票
這才是正確的結果,這是由于當t1要執行標記2(代碼中紅色已標明)的時候,首先會判斷該地址是否被鎖住,如果沒有被鎖住,就會執行coount--,而此時t1的時間片用完了,t2開始執行,當t2執行到標記2的時候,首先判斷該地址是否被鎖住,發現該地址已經被鎖住了,于是t2等待鎖的釋放,當t2的時間片用完時,t1開始繼續執行,此時接著上次執行的位置執行,輸出count的值,然后釋放鎖,此時當t1的時間片用完后,t2發現該地址的鎖被釋放了,于是t2拿到該鎖,然后進去執行。。。以此類推。將會正確輸出結果。
只有該this所指向的地址相同時synchronized代碼塊才會起到作用,比如,將count的類型改為Integer,synchronized代碼塊傳入count的地址,核心代碼如下:
Integer count = 10;
synchronized (count) { count--; //標記3 System.out.println(Thread.currentThread().getName() + ":還剩余" + count + "張車票");}
結果輸出:
Thread-1:還剩余8張車票Thread-0:還剩余9張車票Thread-1:還剩余6張車票Thread-0:還剩余6張車票Thread-0:還剩余5張車票Thread-1:還剩余4張車票Thread-0:還剩余2張車票Thread-1:還剩余2張車票Thread-0:還剩余1張車票Thread-1:還剩余0張車票
結果解析:
假如現在count=4,t1將count的地址鎖住后,執行完標記3后count=3,假設此時t1時間片用完,而此時t2開始執行,t2首先判斷count的地址是否被鎖住,發現此時count的地址并沒有被鎖住,這是因為t1鎖住的是count=4的地址,而此時t2判斷的是count=3的地址是否被鎖住,而count=3的地址并沒有被鎖住,所以t2會執行代碼塊中的代碼,執行完標記3后count=2,然后輸出還剩余2張車票,當t2的時間片用完后,t1開始繼續執行輸出還剩余2張車票,所以出現上述的現象。就是因為count的地址是變化的,所以一般給synchronized傳入的參數是一個不可變的地址,比如類的字節碼
新聞熱點
疑難解答