Table of Contents
ToggleSynchronization in Java with Examples
同步是控制多個執行緒訪問任何共享資源的能力,如果希望只允許一個執行緒訪問共享資源,使用 Synchronized 是其中的一個選擇,使用方法是需要指定一個物件,當程式進入 Synchronized 區塊或方法時,該物件會被鎖定,直到離開 Synchronized 區塊或方法時才會被釋放, Synchronization in Java 本篇增加了範例,並透過單元測試來驗證產出結果。
檔案目錄
./
+- src
+- test
| +- org
| +- ruoxue
| +- java_147
| +- synchronization
| +- SynchronizationWithExamplesTest.java
單元測試
Synchronization Java 提供同步等操作。
noSync
建立 3 個執行緒,不加 synchronized ,對計數器加 1 ,然後結束任務,最終結果會不如預期。
protected class NoSyncCounter {
private int count;
public NoSyncCounter() {
}
public void increment() {
count = getCount() + 1;
System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
}
public int getCount() {
return count;
}
}
@Test
public void noSync() {
int expected = 1000;
int taskSize = 1000;
ExecutorService executorService = Executors.newFixedThreadPool(3);
NoSyncCounter counter = new NoSyncCounter();
IntStream.range(0, taskSize).forEach(e -> {
executorService.submit(counter::increment);
});
executorService.shutdown();
try {
if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
int count = counter.getCount();
System.out.println(count);
assertEquals(expected, count);
}
T[12] count: 997
T[12] count: 998
T[12] count: 999
T[13] count: 989
T[11] count: 933
999
syncMethod
Synchronization Java 建立 3 個執行緒,在方法上加 synchronized ,對計數器加 1 ,然後結束任務。
protected class SyncMethodCounter {
private int count;
public SyncMethodCounter() {
}
public synchronized void increment() {
count = getCount() + 1;
System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
}
public int getCount() {
return count;
}
}
@Test
public void syncMethod() {
int expected = 1000;
int taskSize = 1000;
ExecutorService executorService = Executors.newFixedThreadPool(3);
SyncMethodCounter counter = new SyncMethodCounter();
IntStream.range(0, taskSize).forEach(e -> {
executorService.submit(counter::increment);
});
executorService.shutdown();
try {
if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
int count = counter.getCount();
System.out.println(count);
assertEquals(expected, count);
}
T[12] count: 996
T[12] count: 997
T[12] count: 998
T[13] count: 999
T[11] count: 1000
1000
syncBlock
Synchronization Java 建立 3 個執行緒,在區塊上加 synchronized ,對計數器加 1 ,然後結束任務。
protected class SyncBlockCounter {
private int count;
public SyncBlockCounter() {
}
public void increment() {
synchronized (this) {
count = getCount() + 1;
System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
}
}
public int getCount() {
return count;
}
}
@Test
public void syncBlock() {
int expected = 1000;
int taskSize = 1000;
ExecutorService executorService = Executors.newFixedThreadPool(3);
SyncBlockCounter counter = new SyncBlockCounter();
IntStream.range(0, taskSize).forEach(e -> {
executorService.submit(counter::increment);
});
executorService.shutdown();
try {
if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
int count = counter.getCount();
System.out.println(count);
assertEquals(expected, count);
}
T[11] count: 996
T[11] count: 997
T[11] count: 998
T[13] count: 999
T[12] count: 1000
1000
SynchronizationWithExamplesTest.java
Java Synchronization 新增單元測試,驗證是否符合預期。
package org.ruoxue.java_147.synchronization;
import static org.junit.Assert.assertEquals;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import org.junit.Test;
public class SynchronizationWithExamplesTest {
protected class NoSyncCounter {
private int count;
public NoSyncCounter() {
}
public void increment() {
count = getCount() + 1;
System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
}
public int getCount() {
return count;
}
}
@Test
public void noSync() {
int expected = 1000;
int taskSize = 1000;
ExecutorService executorService = Executors.newFixedThreadPool(3);
NoSyncCounter counter = new NoSyncCounter();
IntStream.range(0, taskSize).forEach(e -> {
executorService.submit(counter::increment);
});
executorService.shutdown();
try {
if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
int count = counter.getCount();
System.out.println(count);
assertEquals(expected, count);
}
protected class SyncMethodCounter {
private int count;
public SyncMethodCounter() {
}
public synchronized void increment() {
count = getCount() + 1;
System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
}
public int getCount() {
return count;
}
}
@Test
public void syncMethod() {
int expected = 1000;
int taskSize = 1000;
ExecutorService executorService = Executors.newFixedThreadPool(3);
SyncMethodCounter counter = new SyncMethodCounter();
IntStream.range(0, taskSize).forEach(e -> {
executorService.submit(counter::increment);
});
executorService.shutdown();
try {
if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
int count = counter.getCount();
System.out.println(count);
assertEquals(expected, count);
}
protected class SyncBlockCounter {
private int count;
public SyncBlockCounter() {
}
public void increment() {
synchronized (this) {
count = getCount() + 1;
System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
}
}
public int getCount() {
return count;
}
}
@Test
public void syncBlock() {
int expected = 1000;
int taskSize = 1000;
ExecutorService executorService = Executors.newFixedThreadPool(3);
SyncBlockCounter counter = new SyncBlockCounter();
IntStream.range(0, taskSize).forEach(e -> {
executorService.submit(counter::increment);
});
executorService.shutdown();
try {
if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
int count = counter.getCount();
System.out.println(count);
assertEquals(expected, count);
}
}
心得分享
Synchronization Thread in Java 訪問共享資源時提供方法同步,操作共享資源的程式碼被 Synchronized 所包圍,這會鎖定當前工作執行緒,並阻止所有其他試圖鎖定共享資源的執行緒,待 Synchronized 區塊執行完釋放鎖後,鎖定同一物件的其他執行緒,才有機會進行鎖定, Java Synchronization 提供了幾種 Synchronized 常見方法的操作範例。。