在Java中,Semaphore
和CountDownLatch
都是用於線程同步的工具類,但它們的應用場景不同。Semaphore
用於控制同時訪問某些資源的線程數量,而CountDownLatch
用於等待一組線程完成他們的操作。
如果我們想要讓一定數量的線程等待直到另外一定數量的線程完成他們的任務,我們可以將CountDownLatch
和Semaphore
組合使用。
Java 信號量(semaphore)搭配CountDownLatch 實現多線程處理循環內邏輯並限制創建線程數
- 使用場景
for循環中的處理邏輯較慢,這個時候可以在for循環中創建線程實現多線程處理數據,結合CountDownLatch 可以等待所有線程全部執行結束之後主線程再執行。
但是有的時候循環次數比較多,並不適合循環創建,因爲線程會創建太多。
比如下面這段代碼
ExecutorService threadPools = Executors.newFixedThreadPool(20);
CountDownLatch countDownLatch = new CountDownLatch(100);
for (int i = 0; i < 100; i++) {
final int token = i;
threadPools.execute(()->{
try {
System.out.println("線程" + Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
countDownLatch.countDown();
}
});
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
- 這時循環100次會執行100個任務,如果循環次數特別大,會直接導致系統內存佔滿死機。
這個時候可以使用信號量來限制任務執行的次視
代碼
@Service
public class XxlService {
private final Semaphore semaphore = new Semaphore(10);
private final ExecutorService threadPools = Executors.newFixedThreadPool(20);
public void syncSaiWordData() {
// 2. 創建計數器
CountDownLatch countDownLatch = new CountDownLatch(needSyncDataList.size());
// 4. 開啓多線程完善數據 最多10條線程
for (WordSaiwordLibraryPO wordSaiwordLibraryPO : needSyncDataList) {
threadPools.execute(() -> {
try {
// 獲取許可
semaphore.acquire();
// 已經補全信息的無需再次查詢
// 處理業務邏輯...
// ...
} catch (Exception e) {
e.printStackTrace();
} finally {
// 歸還許可
semaphore.release();
//計數器 -1
countDownLatch.countDown();
}
});
}
try {
// 等待全部執行結束
countDownLatch.await();
//needSyncDataList.size()個數的線程全部執行完之後,繼續處理下面邏輯
....
} catch (InterruptedException e) {
e.printStackTrace();
}
}