最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

為什么程序中突然多了 200 個(gè) Dubbo-thread 線(xiàn)程的說(shuō)明

 更新時(shí)間:2020年09月25日 10:47:05   作者:回歸心靈  
這篇文章主要介紹了為什么程序中突然多了 200 個(gè) Dubbo-thread 線(xiàn)程的說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

背景

在某次查看程序線(xiàn)程堆棧信息時(shí),偶然發(fā)現(xiàn)有 200 個(gè) Dubbo-thread 線(xiàn)程,而且大部分都處于 WAITING 狀態(tài),如下所示:

"Dubbo-thread-200" #160932 daemon prio=5 os_prio=0 tid=0x00007f5af9b54800 nid=0x79a6 waiting on condition [0x00007f5a9acd5000]
  java.lang.Thread.State: WAITING (parking)
 at sun.misc.Unsafe.park(Native Method)
 - parking to wait for <0x00000000c78f1240> (a java.util.concurrent.SynchronousQueue$TransferStack)
 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
 at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
 at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:924)
 at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at java.lang.Thread.run(Thread.java:748)

  Locked ownable synchronizers:
 - None

為什么會(huì)有這么多 Dubbo-thread 線(xiàn)程呢?這些線(xiàn)程有什么作用呢?帶著疑問(wèn)就去研究了下源碼。

源碼分析

Dubbo (2.7.5 版本)的線(xiàn)程池 ThreadPool 有四種具體的實(shí)現(xiàn)類(lèi)型:

fixed=org.apache.dubbo.common.threadpool.support.fixed.FixedThreadPool
cached=org.apache.dubbo.common.threadpool.support.cached.CachedThreadPool
limited=org.apache.dubbo.common.threadpool.support.limited.LimitedThreadPool
eager=org.apache.dubbo.common.threadpool.support.eager.EagerThreadPool

程序通過(guò)調(diào)用具體實(shí)現(xiàn)類(lèi)的 getExecutor(URL url) 方法來(lái)創(chuàng)建線(xiàn)程池。而調(diào)用該方法的只有 DefaultExecutorRepository 類(lèi)的 createExecutor 方法,該方法會(huì)根據(jù) url 上的參數(shù) threadpool=cached 來(lái)決定創(chuàng)建那種類(lèi)型的線(xiàn)程池。createExecutor 是一個(gè)私有方法,調(diào)用它的有下面兩個(gè)方法:

 /**
   * Get called when the server or client instance initiating.
   *
   * @param url
   * @return
   */
  public synchronized ExecutorService createExecutorIfAbsent(URL url) {
    String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY;
    if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
      componentKey = CONSUMER_SIDE;
    }
    Map<Integer, ExecutorService> executors = data.computeIfAbsent(componentKey, k -> new ConcurrentHashMap<>());
    Integer portKey = url.getPort();
    ExecutorService executor = executors.computeIfAbsent(portKey, k -> createExecutor(url));
    // If executor has been shut down, create a new one
    if (executor.isShutdown() || executor.isTerminated()) {
      executors.remove(portKey);
      executor = createExecutor(url);
      executors.put(portKey, executor);
    }
    return executor;
  }

  public ExecutorService getExecutor(URL url) {
    String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY;
    if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
      componentKey = CONSUMER_SIDE;
    }
    Map<Integer, ExecutorService> executors = data.get(componentKey);

    /**
     * It's guaranteed that this method is called after {@link #createExecutorIfAbsent(URL)}, so data should already
     * have Executor instances generated and stored.
     */
    if (executors == null) {
      logger.warn("No available executors, this is not expected, framework should call createExecutorIfAbsent first " +
          "before coming to here.");
      return null;
    }

    Integer portKey = url.getPort();
    ExecutorService executor = executors.get(portKey);
    if (executor != null) {
      if (executor.isShutdown() || executor.isTerminated()) {
        executors.remove(portKey);
        executor = createExecutor(url);
        executors.put(portKey, executor);
      }
    }
    return executor;
  }

對(duì)于上面第一個(gè)方法,備注已經(jīng)說(shuō)明在服務(wù)提供者或者服務(wù)消費(fèi)者初始化的時(shí)候會(huì)調(diào)用,通過(guò)debug 可以得出:服務(wù)提供者初始化會(huì)創(chuàng)建線(xiàn)程名為 DubboServerHandler-10.12.16.67:20880-thread 的線(xiàn)程池,服務(wù)消費(fèi)者會(huì)創(chuàng)建線(xiàn)程名為 DubboClientHandler-10.12.16.67:20880-thread 的線(xiàn)程池。

這里需要說(shuō)明下,Dubbo 創(chuàng)建的線(xiàn)程池會(huì)存儲(chǔ)在 Map 中共享使用:

private ConcurrentMap<String, ConcurrentMap<Integer, ExecutorService>> data = new ConcurrentHashMap<>();

外面的 key 表示服務(wù)提供方還是消費(fèi)方,里面的 key 表示服務(wù)暴露的端口號(hào),也就是說(shuō)消費(fèi)方對(duì)于相同端口號(hào)的服務(wù)只會(huì)創(chuàng)建一個(gè)線(xiàn)程池,共享同一個(gè)線(xiàn)程池進(jìn)行服務(wù)請(qǐng)求和消息接收后一系列處理。

顯然和 Dubbo-thread 名不一樣,那就很有可能是通過(guò)調(diào)用第二個(gè)方法創(chuàng)建的線(xiàn)程池。第二個(gè)方法的調(diào)用往上追溯就比較分散了,找不到什么有用的信息。

再看方法具體內(nèi)容,當(dāng)已經(jīng)創(chuàng)建的線(xiàn)程池關(guān)閉或終止時(shí)會(huì)重新創(chuàng)建新的線(xiàn)程池。然后就推測(cè)什么情況下線(xiàn)程池會(huì)被關(guān)閉或終止,在服務(wù)重啟后輸出堆棧信息并沒(méi)有 Dubbo-thread 線(xiàn)程,然后就猜測(cè)消費(fèi)方和提供方連接斷開(kāi)會(huì)不會(huì)觸發(fā)線(xiàn)程池關(guān)閉,于是重啟了服務(wù)提供方,果然重現(xiàn)了Dubbo-thread 線(xiàn)程。

然后在 Dubbo 的具體線(xiàn)程池創(chuàng)建方法中添加日志,輸出調(diào)用棧信息(通過(guò)產(chǎn)生一個(gè)異常輸出調(diào)用信息)。

如下圖:

在這里插入圖片描述可以看到當(dāng) channel 失效時(shí)會(huì)調(diào)用 disconnected 方法,最終會(huì)調(diào)用 DefaultExecutorRepository 類(lèi)的 getExecutor 創(chuàng)建線(xiàn)程池,當(dāng)服務(wù)提供者重啟時(shí),消費(fèi)方相應(yīng)的線(xiàn)程池會(huì)被shutdown。

重現(xiàn)創(chuàng)建線(xiàn)程池所用的 URL 是 WrappedChannelHandler 類(lèi)的 URL,該值是在服務(wù)啟動(dòng)初始化時(shí)設(shè)置的,該值的設(shè)置要早于 AbstractClient 客戶(hù)端 Executor 初始化。

因此由于 channel 斷開(kāi)而重新創(chuàng)建的線(xiàn)程池所用的 URL 和客戶(hù)端初始創(chuàng)建線(xiàn)程池用的 URL 可能是不同的,特別是在沒(méi)有配置 consumer 的線(xiàn)程池類(lèi)型時(shí),初始創(chuàng)建的 Cached 類(lèi)型線(xiàn)程池,線(xiàn)程名稱(chēng)是 DubboClientHandler…。

而重新創(chuàng)建所用 URL 是沒(méi)有經(jīng)過(guò)下面方法設(shè)置的,因此就會(huì)創(chuàng)建默認(rèn)類(lèi)型為 fixed 的線(xiàn)程池,線(xiàn)程數(shù)為默認(rèn) 200,線(xiàn)程名為 Dubbo…。

private void initExecutor(URL url) {
    url = ExecutorUtil.setThreadName(url, CLIENT_THREAD_POOL_NAME);
    url = url.addParameterIfAbsent(THREADPOOL_KEY, DEFAULT_CLIENT_THREADPOOL);
    executor = executorRepository.createExecutorIfAbsent(url);
  }

總結(jié)

那么,就可以知道 Dubbo-thread 線(xiàn)程池的創(chuàng)建是由于服務(wù)消費(fèi)方和提供方之間連接斷開(kāi)而創(chuàng)建的線(xiàn)程池,代替程序啟動(dòng)初始化時(shí)創(chuàng)建的 DubboClientHandler 線(xiàn)程池。主要做一些 channel 斷開(kāi)后續(xù)一些處理,還有接收服務(wù)端消息后的反序列化等操作,具體的可以看類(lèi) ThreadlessExecutor(同步調(diào)用處理類(lèi)) 、ChannelEventRunnable(channel 不同狀態(tài)處理,包括:連接、接收到消息、斷開(kāi)鏈接等)。

還有一個(gè)要注意到點(diǎn)是,如果沒(méi)有配置consumer.threadpool 類(lèi)型、therads 等信息,那么斷開(kāi)連接后再創(chuàng)建的線(xiàn)程池將會(huì)是 fixed 類(lèi)型的線(xiàn)程池,線(xiàn)程數(shù)為默認(rèn) 200。

以上這篇為什么程序中突然多了 200 個(gè) Dubbo-thread 線(xiàn)程的說(shuō)明就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java抓取網(wǎng)頁(yè)數(shù)據(jù)獲取網(wǎng)頁(yè)中所有的鏈接實(shí)例分享

    java抓取網(wǎng)頁(yè)數(shù)據(jù)獲取網(wǎng)頁(yè)中所有的鏈接實(shí)例分享

    java抓取網(wǎng)頁(yè)數(shù)據(jù)獲取網(wǎng)頁(yè)中所有的鏈接實(shí)例分享,使用方法,只要實(shí)例化HtmlParser時(shí)傳入網(wǎng)頁(yè)地址就可以了
    2013-12-12
  • Java Springboot整合支付寶接口的教程詳解

    Java Springboot整合支付寶接口的教程詳解

    這篇文章主要為大家詳細(xì)介紹了Java Springboot實(shí)現(xiàn)整合支付寶接口的教程,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,需要的可以參考一下
    2023-02-02
  • java線(xiàn)程的基礎(chǔ)實(shí)例解析

    java線(xiàn)程的基礎(chǔ)實(shí)例解析

    java中線(xiàn)程的基本方法的熟練使用是精通多線(xiàn)程編程的必經(jīng)之路,線(xiàn)程相關(guān)的基本方法有wait,notify,notifyAll,sleep,join,yield等,本文淺要的介紹一下它們的使用方式
    2021-06-06
  • Java IO中字節(jié)流復(fù)制圖片實(shí)現(xiàn)代碼

    Java IO中字節(jié)流復(fù)制圖片實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java IO中字節(jié)流復(fù)制圖片實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • java中Pulsar?InterruptedException?異常

    java中Pulsar?InterruptedException?異常

    這篇文章主要為大家介紹了java中Pulsar?InterruptedException?異常分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Java 8中default方法能做什么?不能做什么?

    Java 8中default方法能做什么?不能做什么?

    這篇文章主要給大家介紹了關(guān)于Java 8中default方法能做什么?不能做什么?文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-04-04
  • Maven倉(cāng)庫(kù)的具體使用(本地倉(cāng)庫(kù)+遠(yuǎn)程倉(cāng)庫(kù))

    Maven倉(cāng)庫(kù)的具體使用(本地倉(cāng)庫(kù)+遠(yuǎn)程倉(cāng)庫(kù))

    Maven 在某個(gè)統(tǒng)一的位置存儲(chǔ)所有項(xiàng)目的構(gòu)件,這個(gè)統(tǒng)一的位置,我們就稱(chēng)之為倉(cāng)庫(kù),本文主要介紹了Maven倉(cāng)庫(kù)的具體使用(本地倉(cāng)庫(kù)+遠(yuǎn)程倉(cāng)庫(kù)),感興趣的可以了解一下
    2023-11-11
  • SpringBoot中的CSRF攻擊及預(yù)防方法

    SpringBoot中的CSRF攻擊及預(yù)防方法

    CSRF攻擊是一種常見(jiàn)的網(wǎng)絡(luò)攻擊方式,可以通過(guò)欺騙用戶(hù)來(lái)執(zhí)行惡意操作,在Spring Boot應(yīng)用程序中,我們可以采取多種措施來(lái)預(yù)防CSRF攻擊,本文將給大家介紹一下CSRF攻擊以及如何預(yù)防攻擊,需要的朋友可以參考下
    2023-07-07
  • Java中的動(dòng)態(tài)代理實(shí)現(xiàn)代碼實(shí)例

    Java中的動(dòng)態(tài)代理實(shí)現(xiàn)代碼實(shí)例

    這篇文章主要介紹了Java中的動(dòng)態(tài)代理實(shí)現(xiàn)代碼實(shí)例,jdk動(dòng)態(tài)代理本質(zhì)上是使用被代理對(duì)象的類(lèi)加載器,通過(guò)被代理類(lèi)實(shí)現(xiàn)的接口在運(yùn)行時(shí)動(dòng)態(tài)構(gòu)造出代理類(lèi)來(lái)增強(qiáng)原始類(lèi)的功能的方法,需要的朋友可以參考下
    2023-12-12
  • java微信掃描公眾號(hào)二維碼實(shí)現(xiàn)登陸功能

    java微信掃描公眾號(hào)二維碼實(shí)現(xiàn)登陸功能

    這篇文章主要為大家詳細(xì)介紹了PHP微信掃描公眾號(hào)二維碼實(shí)現(xiàn)登陸功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07

最新評(píng)論

定兴县| 滕州市| 景泰县| 墨脱县| 大名县| 开远市| 德惠市| 莲花县| 顺昌县| 阿尔山市| 富源县| 阿拉善右旗| 伊宁市| 宜兴市| 兴海县| 贡觉县| 淄博市| 琼中| 九江市| 南雄市| 威宁| 长垣县| 五大连池市| 龙岩市| 栾川县| 绥江县| 广宗县| 垣曲县| 襄垣县| 南和县| 平塘县| 嘉黎县| 长治市| 平遥县| 板桥市| 孟连| 依安县| 万全县| 宾川县| 海丰县| 泗洪县|