自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

沒看過ReentrantLock源碼,別說精通Java并發(fā)編程

開發(fā) 前端
看完了CountDownLatch的所有源碼,是不是覺得CountDownLatch邏輯很簡單。因為加鎖流程的編排工作已經(jīng)在父類AQS中實現(xiàn),子類只需要實現(xiàn)具體的加鎖邏輯即可,也就是實現(xiàn)tryReleaseShared()方法和tryAcquireShared()方法。而加鎖邏輯也很簡單,也就是修改同步狀態(tài)state的值即可。

引言

高手程序員與新手程序員一個簡單的判斷標(biāo)準(zhǔn),就是有沒有使用過CountDownLatch,在互聯(lián)網(wǎng)公司工作超過3年的程序員基本上應(yīng)該都用過。CountDownLatch中文名稱叫做閉鎖,也叫計數(shù)鎖,不過不是用來加鎖的,而是通過計數(shù)實現(xiàn)條件等待的功能。CountDownLatch的使用場景有兩個:

  1. 當(dāng)前線程等待其他線程都執(zhí)行完成之后,再執(zhí)行。
  2. 所有線程滿足條件后,再一起執(zhí)行。

使用示例

CountDownLatch常用的方法就兩個,countDown()方法用來將計數(shù)器減一,await()方法會阻塞當(dāng)前線程,直到計數(shù)器值等于0。

場景1:

先看一下第一種場景,也是最常用的場景:

  • 當(dāng)前線程等待其他線程都執(zhí)行完成之后,再執(zhí)行。

在工作中什么時候會遇到這種場景呢?比如當(dāng)前線程需要查詢3個數(shù)據(jù)庫,并且把查詢結(jié)果匯總返回給前端。查詢3個數(shù)據(jù)庫的邏輯,可以分別使用3個線程加快查詢速度。但是怎么判斷3個線程都執(zhí)行結(jié)束了呢?這時候就可以使用CountDownLatch了。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 一燈架構(gòu)
 * @apiNote CountDownLatch測試類(場景1)
 **/
public class CountDownLatchTest1 {

    public static void main(String[] args) throws InterruptedException {

        // 1. 創(chuàng)建一個線程池,用來執(zhí)行3個查詢?nèi)蝿?wù)
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 2. 創(chuàng)建一個計數(shù)鎖,數(shù)量是3
        CountDownLatch countDownLatch = new CountDownLatch(3);

        // 3. 啟動3個查詢?nèi)蝿?wù)
        for (int i = 0; i < 3; i++) {
            executorService.submit(() -> {
                try {
                    // 4. 睡眠1秒,模擬任務(wù)執(zhí)行過程
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " 執(zhí)行完成");
                    // 5. 任務(wù)執(zhí)行完成,計數(shù)器減一
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                }
            });
        }

        // 6. 等待所有任務(wù)執(zhí)行完成
        countDownLatch.await();
        System.out.println("所有任務(wù)執(zhí)行完成。");

        // 7. 關(guān)閉線程池
        executorService.shutdown();
    }
}

輸出結(jié)果:

pool-1-thread-2 執(zhí)行完成 pool-1-thread-1 執(zhí)行完成 pool-1-thread-3 執(zhí)行完成 所有任務(wù)執(zhí)行完成。

需要注意的是,這里創(chuàng)建CountDownLatch計數(shù)器的時候,指定的數(shù)量是3,因為有3個任務(wù)。在3個任務(wù)沒有執(zhí)行完成之前,await()方法會一直阻塞,直到3個任務(wù)都執(zhí)行完成。

場景2

再看一下第二種場景,有些情況用的也比較多:

  • 所有線程滿足條件后,再一起執(zhí)行。

什么情況下會遇到這種場景呢?比如系統(tǒng)中多個任務(wù)線程存在先后依賴關(guān)系,必須等待其他線程啟動完成后,才能一起執(zhí)行。

/**
 * @author 一燈架構(gòu)
 * @apiNote CountDownLatch測試類(場景2)
 **/
public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {

        // 1. 創(chuàng)建一個線程池,用來執(zhí)行3個任務(wù)
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 2. 創(chuàng)建一個計數(shù)鎖,數(shù)量是1
        CountDownLatch countDownLatch = new CountDownLatch(1);

        // 3. 啟動3個任務(wù)
        for (int i = 0; i < 3; i++) {
            executorService.submit(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " 啟動完成");
                    // 4. 等待其他任務(wù)啟動完成
                    countDownLatch.await();
                    // 5. 睡眠1秒,模擬任務(wù)執(zhí)行過程
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " 執(zhí)行完成");
                } catch (InterruptedException e) {
                }
            });
        }

        // 6. 所有任務(wù)啟動完成,計數(shù)器減一
        countDownLatch.countDown();
        System.out.println("所有任務(wù)啟動完成,開始執(zhí)行。");

        // 7. 關(guān)閉線程池
        executorService.shutdown();
    }
}

輸出結(jié)果:

pool-1-thread-1 啟動完成 pool-1-thread-2 啟動完成 pool-1-thread-3 啟動完成 所有任務(wù)啟動完成,開始執(zhí)行。 pool-1-thread-1 執(zhí)行完成 pool-1-thread-3 執(zhí)行完成 pool-1-thread-2 執(zhí)行完成

需要注意的是,與場景1不同,這里創(chuàng)建CountDownLatch計數(shù)器的時候,指定的數(shù)量是1,因為3個任務(wù)需要滿足同一個條件,就是都啟動完成,也就是只需要調(diào)用一次countDown()方法。 看完了CountDownLatch的使用方式,再看一下CountDownLatch的源碼實現(xiàn)。

類屬性

public class CountDownLatch {

    // 只有一個Sync同步變量
    private final Sync sync;

    // Sync繼承自AQS,主要邏輯都在這里面
    private static final class Sync extends AbstractQueuedSynchronizer {

        // 只有這一個構(gòu)造方法,需要指定計數(shù)器數(shù)值
        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        protected boolean tryReleaseShared(int releases) {
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

}

跟ReentrantLock一樣,CountDownLatch也沒有直接繼承AQS,也是采用組合的方式,使用Sync同步變量實現(xiàn)計數(shù)的功能,而Sync同步變量才是真正繼承AQS的。

countDown方法源碼

public void countDown() {
    // 底層調(diào)用父類AQS中的releaseShared()方法
    sync.releaseShared(1);
}

countDown()方法里面調(diào)用的是父類AQS中的releaseShared()方法,而releaseShared()方法又在調(diào)用子類Sync中tryReleaseShared()方法。

/**
 * 父類AQS
 */
public abstract class AbstractQueuedSynchronizer
        extends AbstractOwnableSynchronizer
        implements java.io.Serializable {
            
    public final boolean releaseShared(int arg) {
        // tryReleaseShared()由子類實現(xiàn)
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

    // 定義抽象方法,由子類實現(xiàn)
    protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
    }
}
/**
 * 子類Sync
 */
private static final class Sync extends AbstractQueuedSynchronizer {
    
    // 實現(xiàn)父類AQS中的tryReleaseShared()方法
    @Override
    protected boolean tryReleaseShared(int releases) {
        for (;;) {
            int c = getState();
            if (c == 0) {
                return false;
            }
            int nextc = c-1;
            if (compareAndSetState(c, nextc)) {
                return nextc == 0;
            }
        }
    }
}

而Sync同步類中tryReleaseShared()方法邏輯也很簡單,就是把同步狀態(tài)state值減一。

await源碼

await()方法底層也是調(diào)用父類中acquireSharedInterruptibly()方法,而父類AQS又需要調(diào)用子類Sync中的具體實現(xiàn)。

public void await() throws InterruptedException {
    // 底層調(diào)用父類AQS中的releaseShared()方法
    sync.acquireSharedInterruptibly(1);
}
/**
 * 父類AQS
 */
public abstract class AbstractQueuedSynchronizer
        extends AbstractOwnableSynchronizer
        implements java.io.Serializable {

    public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        // tryAcquireShared()由子類實現(xiàn)
        if (tryAcquireShared(arg) < 0) {
            doAcquireSharedInterruptibly(arg);
        }
    }

    // 定義抽象方法,由子類實現(xiàn)
    protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }

}

子類Sync只需要實現(xiàn)tryAcquireShared()方法即可,而tryAcquireShared()方法的作用就是判斷鎖是否已經(jīng)完全釋放,即同步狀態(tài)state=0。

/**
 * 子類Sync
 */
private static final class Sync extends AbstractQueuedSynchronizer {

    // 實現(xiàn)父類AQS中的tryAcquireShared()方法
    @Override
    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }
}

總結(jié)

看完了CountDownLatch的所有源碼,是不是覺得CountDownLatch邏輯很簡單。

因為加鎖流程的編排工作已經(jīng)在父類AQS中實現(xiàn),子類只需要實現(xiàn)具體的加鎖邏輯即可,也就是實現(xiàn)tryReleaseShared()方法和tryAcquireShared()方法。而加鎖邏輯也很簡單,也就是修改同步狀態(tài)state的值即可。想要詳細(xì)了解父類AQS的流程,可以翻看前幾篇文章。

下篇文章再一塊學(xué)習(xí)一下共享鎖Semaphore的源碼實現(xiàn)。

責(zé)任編輯:武曉燕 來源: 一燈架構(gòu)
相關(guān)推薦

2024-02-29 09:37:25

Java并發(fā)編程

2023-12-28 07:49:11

線程池源碼應(yīng)用場景

2023-04-06 00:15:03

JavaReentrantL線程

2023-09-12 13:48:47

2019-09-02 08:08:30

緩存HTTP數(shù)據(jù)庫

2024-04-29 09:06:46

線程初始化源碼

2015-09-22 13:08:42

戴爾云計算

2020-11-16 08:11:32

ReentrantLo

2023-05-23 08:54:43

SRESLO運(yùn)營

2017-09-19 14:53:37

Java并發(fā)編程并發(fā)代碼設(shè)計

2022-11-14 11:09:36

源碼AQS加鎖

2020-08-24 08:13:25

非公平鎖源碼

2011-12-29 13:31:15

Java

2021-09-01 17:51:53

技術(shù)LinkedList 源碼

2025-02-19 00:05:18

Java并發(fā)編程

2025-02-17 00:00:25

Java并發(fā)編程

2021-09-02 09:53:42

開發(fā)Redis配置

2022-11-27 08:12:11

RocketMQ源碼工具類

2019-08-21 08:01:24

計算機(jī)視覺人工智能深度學(xué)習(xí)

2020-01-22 16:29:52

機(jī)器學(xué)習(xí)人工智能計算機(jī)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號