【Java併發】【AQS鎖】鎖在原始碼中的應用

酷酷-發表於2024-10-24

1 前言

本節主要記錄下基於 AQS 衍生出來的一些常用鎖比如:CountDownLatch、‌‌ReentrantLock、Semaphore、‌‌ReentrantReadWriteLock 等他們在原始碼中的一些應用,好記性不如爛筆頭。‌

2 CountDownLatch

2.1 RocketMQ 中 Broker 向 所有NameServer 的註冊

RocketMQ 路由註冊是透過 Broker 與 NameServer 的心跳功能實現的。 Broker啟動時向叢集中所有的NameServ巳r傳送心跳語句,每隔 30s 向叢集中所有NameServer傳送心跳包, NameServer 收到 Broker 心跳包時會更新 brokerLiveTable 快取中 BrokerLivelnfo 的 lastUpdateTimestamp ,然後 Nam巳 Server 每隔 10s 掃描 brokerLiveTable,如果連續 !20s 沒有收到心跳包, NameServer將移除該Broker 的路由資訊同時關閉 Socket連線。

那麼這裡比如我有 4個 NameServer,是迴圈遍歷一個一個註冊麼?其實不是,這裡就用到了執行緒池 + CountDownLatch,我們看下:

public List<RegisterBrokerResult> registerBrokerAll(
    final String clusterName,
    final String brokerAddr,
    final String brokerName,
    final long brokerId,
    final String haServerAddr,
    final TopicConfigSerializeWrapper topicConfigWrapper,
    final List<String> filterServerList,
    final boolean oneway,
    final int timeoutMills,
    final boolean enableActingMaster,
    final boolean compressed,
    final Long heartbeatTimeoutMillis,
    final BrokerIdentity brokerIdentity) {
    final List<RegisterBrokerResult> registerBrokerResultList = new CopyOnWriteArrayList<>();
    List<String> nameServerAddressList = this.remotingClient.getAvailableNameSrvList();
    if (nameServerAddressList != null && nameServerAddressList.size() > 0) {
        final RegisterBrokerRequestHeader requestHeader = new RegisterBrokerRequestHeader();
        requestHeader.setBrokerAddr(brokerAddr);
        requestHeader.setBrokerId(brokerId);
        requestHeader.setBrokerName(brokerName);
        requestHeader.setClusterName(clusterName);
        requestHeader.setHaServerAddr(haServerAddr);
        requestHeader.setEnableActingMaster(enableActingMaster);
        requestHeader.setCompressed(false);
        if (heartbeatTimeoutMillis != null) {
            requestHeader.setHeartbeatTimeoutMillis(heartbeatTimeoutMillis);
        }
        RegisterBrokerBody requestBody = new RegisterBrokerBody();
        requestBody.setTopicConfigSerializeWrapper(TopicConfigAndMappingSerializeWrapper.from(topicConfigWrapper));
        requestBody.setFilterServerList(filterServerList);
        final byte[] body = requestBody.encode(compressed);
        final int bodyCrc32 = UtilAll.crc32(body);
        requestHeader.setBodyCrc32(bodyCrc32);
        // 建立一個計數器鎖(數量為 nameServer 的個數)
        final CountDownLatch countDownLatch = new CountDownLatch(nameServerAddressList.size());
        // 迴圈遍歷
        for (final String namesrvAddr : nameServerAddressList) {
            // 往執行緒池中扔任務
            brokerOuterExecutor.execute(new AbstractBrokerRunnable(brokerIdentity) {
                @Override
                public void run0() {
                    try {
                        RegisterBrokerResult result = registerBroker(namesrvAddr, oneway, timeoutMills, requestHeader, body);
                        if (result != null) {
                            registerBrokerResultList.add(result);
                        }
                        LOGGER.info("Registering current broker to name server completed. TargetHost={}", namesrvAddr);
                    } catch (Exception e) {
                        LOGGER.error("Failed to register current broker to name server. TargetHost={}", namesrvAddr, e);
                    } finally {
                        // 計數器減1
                        countDownLatch.countDown();
                    }
                }
            });
        }
        try {
            // 超時等待都註冊完畢
            if (!countDownLatch.await(timeoutMills, TimeUnit.MILLISECONDS)) {
                LOGGER.warn("Registration to one or more name servers does NOT complete within deadline. Timeout threshold: {}ms", timeoutMills);
            }
        } catch (InterruptedException ignore) {
        }
    }
    return registerBrokerResultList;
}

可以看到是透過遍歷,向執行緒池中執行任務,每個執行緒註冊完會讓鎖減1,最後下邊 await 等待所有的執行緒都註冊完畢。

3 ReentrantLock

4 Semaphore

5 ReentrantReadWriteLock

6 小結

歸納總結是對技術的鞏固以及認識的增強,看看人家別人怎麼用的,什麼場景下用的,用法上跟自己的有什麼不同,甚至在自己寫業務的時候,是不是能直接借鑑下,哈哈哈,受益頗多都,所以大家也要學會總結積累哈。本節就主要記錄下鎖的一些原始碼應用(會持續增加),有理解不對的地方歡迎指正哈。

相關文章