爲了便於理解先來看看沒有加同步代碼塊的 2 組同樣功能的代碼在不同狀態下的執行結果,下面看第一組:
package cn.sunzn.synchronize; public class SynchronizeCode { public static void main(String[] args) { new Thread() { public void run() { while (true) { System.out.println("同步代碼"); } }; }.start(); new Thread() { public void run() { while (true) { System.out.println("SynchronizeCode"); } }; }.start(); } }
第一組代碼運行結果:
SynchronizeCode
SynchronizeCode
SynchronizeCode
SynchronizeCode
同步代碼
同步代碼
同步代碼
同步代碼
下面再來看第 2 組代碼:
package cn.sunzn.synchronize; public class SynchronizeCode { public static void main(String[] args) { new Thread() { public void run() { while (true) { System.out.print("同步"); System.out.println("代碼"); } }; }.start(); new Thread() { public void run() { while (true) { System.out.print("Synchronize"); System.out.println("Code"); } }; }.start(); } }
第二組代碼運行結果:
同步代碼
同步代碼
同步代碼
同步Code
SynchronizeCode
SynchronizeCode
SynchronizeCode
SynchronizeCode
顯然,第二組代碼中同一個線程下的打印輸出並沒有同時執行,這是因爲 CPU 在不同的線程間進行切換時的隨機性導致的。第二組代碼中的輸出結果“同步Code”是因爲 CPU 切換到線程 1 的時候打印輸出“同步”,但是當程序正準備打印“代碼”的時候,CUP 切換到了線程 2 打印輸出“Code”, 然後線程 2 繼續持有 CPU 資源進行打印輸出,知道 CPU 切換到線程 1。正因爲這樣的原因,當程序中包含有多個線程時,導致了同一個線程下的代碼不能同時被執行。那麼,我們如何才能保證這樣的情況不發生呢?使用同步代碼 塊。下面我們來看使用了同步代碼塊程序的運行結果:
package cn.sunzn.synchronize; public class SynchronizeCode { public static void main(String[] args) { /************ 創建鎖對象 ************/ final Object lock = new Object(); /************ 開啓線程一 ************/ new Thread() { public void run() { while (true) { synchronized (lock) { System.out.print("同步"); System.out.println("代碼"); } } }; }.start(); /************ 開啓線程二 ************/ new Thread() { public void run() { while (true) { synchronized (lock) { System.out.print("Synchronize"); System.out.println("Code"); } } }; }.start(); } }
運行上面的代碼我們會發現運行結果和第一組代碼的運行結果類似,這是因爲使用了相同鎖對象的同步代碼塊具有原子性,在進行執行的時候會持續的擁有 CPU 資源直到同步代碼塊執行完畢,要麼繼續持有 CPU 資源,要麼 CPU 切換到到另一個線程,這樣保證了在執行一組代碼的時候不會有其他線程插入執行。