同步針對的是多線程。同步的方法或代碼塊同時只能由一個線程執行。
Java支持多線程來執行。這可能會導致兩個或多個線程訪問同一個字段或對象。同步是一個使所有並發執行的線程同步的過程。同步避免了由於共享內存視圖不一致而導致的內存一致性錯誤。當一個方法被聲明為同步時,如果一個線程正在執行同步方法,線程保存該方法對象的監視器(monitor),同時該線程被阻塞,直到該線程釋放監視器(monitor)為止。
同步在Java中使用synchronized關鍵字實現。可以在類中定義的方法或塊使用同步關鍵字。關鍵字不能與類定義中的局部變量一起使用。
對象級別鎖
對象級別鎖是一種當您想同步非靜態方法或非靜態代碼塊時,只有一個線程能夠在類的給定實例上執行代碼塊的機制。應該始終這樣做,使實例級數據線程安全。這可以做如下:
public class DemoClass { public synchronized void demoMethod(){} }
或
public class DemoClass { public void demoMethod(){ synchronized (this) { //other thread safe code } } }
或
public class DemoClass { private final Object lock = new Object(); public void demoMethod(){ synchronized (lock) { //other thread safe code } } }
類級別鎖
類級鎖定防止在運行時多個線程進入所有可用實例中的同步塊中。這意味着,如果在運行時有100 DemoClass實例,那么只有一個線程可以在同一時間在任何一個實例上執行demomethod(),對其他線程而言所有其他的實例將被鎖。這樣做總是為了使靜態數據線程安全。
public class DemoClass { public synchronized static void demoMethod(){} }
或
public class DemoClass { public void demoMethod(){ synchronized (DemoClass.class) { //other thread safe code } } }
或
public class DemoClass { private final static Object lock = new Object(); public void demoMethod(){ synchronized (lock) { //other thread safe code } } }
一些重要的事項
- 在Java中為了保證沒有兩個線程可以同時執行一個同步的方法,這就需要相同的鎖。
- 同步關鍵字只能用於方法,代碼塊和final字段。這些方法或塊既可以是靜態的也可以是非靜態的。
- 當有一個線程進入Java同步方法或塊的時候獲取鎖,離開Java同步方法或塊的時候釋放鎖。線程完成同步方法,或由於任何錯誤或異常,鎖都會被釋放。
- Java同步關鍵詞是可重入的,這意味着如果一個Java同步方法調用另一個需要相同的鎖的同步方法,當前線程持有鎖,能直接進入,不需要有獲取鎖。
- 如果使用Java同步塊的對象為空Java同步將拋出NullPointerException。例如,在上面的代碼示例,如果鎖被初始化為null,同步(鎖)將拋出NullPointerException。
- Java同步會消耗您的應用程序性能。所以絕對必要時才使用同步。另外,考慮使用同步代碼塊來同步代碼中的關鍵部分。
- 靜態同步和非靜態同步方法可能同時或並發地運行,因為它們鎖定在不同的對象上。
- 根據Java語言規范不能使用同步關鍵詞在構造函數上,這是違法的,會導致編譯錯誤。
- 不要同步非final字段。因為非final字段的引用可能隨時改變,不同的線程可能在不同的對象上同步,即根本不同步。最好是使用字符串類,它已經是不可變的,並且聲明為最終的。
Happy Learning !!