synchronized是java中用於同步的關鍵字,其典型的作用域如下所示.
1 對象鎖
@Slf4j
public class SynchronizedExample1 {
private final int loopNum = 20;
// 修飾一個代碼塊
private void test1(int j) {
synchronized (this) {
for (int i = 0; i < loopNum; i++) {
log.info("test1 {} - {}", j, i);
}
}
}
// 修飾一個方法
private synchronized void test2(int num) {
for (int i = 0; i < loopNum; i++) {
log.info("test2 {} - {}", num, i);
}
}
public static void main(String[] args) {
SynchronizedExample1 example1 = new SynchronizedExample1();
SynchronizedExample1 example2 = new SynchronizedExample1();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
example1.test2(1);
});
executorService.execute(() -> {
example2.test2(2);
});
executorService.shutdown();
}
}
1.1 代碼塊修飾(對象)
此時,synchronized用於保證test1函數中的被synchronized大括號包裹的代碼同步執行.
synchronized作用的對象為SynchronizedExample1的對象實例,例如main函數中的example1以及example2.
Tips:
1.example1若在多個線程中被調用,其輸出順序將保證同步,按照1,2,3...19,20的順序執行.
2.若example1與example2均在多個線程中執行,則test1...之間保持同步輸出,test2...之間保持同步輸出,但是test1...與test2...之間輸出不保證順序.
1.2 非靜態函數修飾
synchronized添加於test2函數聲明中,其作用類似於1.1中的代碼塊修飾,區別點僅僅在於其同步代碼塊擴充至整個函數(test2).
2. 類鎖
@Slf4j
public class SynchronizedExample2 {
private static final int loopNum = 20;
// 修飾一個類
private static void test1(int j) {
synchronized (SynchronizedExample2.class) {
for (int i = 0; i < loopNum; i++) {
log.info("test1 {} - {}", j, i);
}
}
}
// 修飾一個靜態方法
private static synchronized void test2(int j) {
for (int i = 0; i < loopNum; i++) {
log.info("test2 {} - {}", j, i);
}
}
public static void main(String[] args) {
SynchronizedExample2 example1 = new SynchronizedExample2();
SynchronizedExample2 example2 = new SynchronizedExample2();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
example1.test1(1);
});
executorService.execute(() -> {
example2.test1(2);
});
}
}
2.1 代碼塊修飾(類)
與1.1中區別在於,synchronized函數修飾的是SynchronizedExample2類.
SynchronizedExample2對象,諸如example1或者example2在任意多的線程中調用test1函數,其輸出順序均會被保證(1,2,3,4...19,20).
2.2 靜態函數修飾
功能與2.1類似,均是對對象加鎖,確保多個類對象調用函數時保持順序.
Tips:
示例中,因為類上加鎖的原因,test1與test2對象保持順序執行,不會出現test1...與test2...交叉出現的現象.
3 synchronized不能被繼承
需要注意,若synchronized修飾於函數中,如1.2以及2.2,若有類繼承於SynchronizedExample1或者SynchronizedExample1,子類對象調用test2不同步.
原因:synchronized非函數簽名,因此無法被繼承,所以無法保證子類調用同步.
PS:
如果您覺得我的文章對您有幫助,可以掃碼領取下紅包,謝謝!

