<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      JAVA JUC干貨之線程池實現原理和源碼詳解(上)

      摘要:分享JAVA JUC線程池干貨,首先描述線程池的基本概念,然后介紹線程工廠和拒絕策略,其次逐步深入線程池實現原理和線程池狀態機,最后結合實戰講解源碼。

      JUC干貨系列目錄:

      1. JAVA JUC干貨之線程池狀態和狀態切換
      2. JAVA JUC干貨之線程池實現原理和源碼詳解(上)
      3. JAVA JUC干貨之線程池實現原理和源碼詳解(下)

      綜述

      ??世界唯一不變的事,就是世界一直在變,而且是瞬息萬變,唯有不斷學習、持續創新和迎接變化,才能立于不敗之地。一位金融公司的CTO曾經問我“為什么使用線程池?線程池是怎樣執行任務的?”我由于對這個知識點掌握的不透徹,只能臨場發揮,導致結局尷尬。因此亡羊補牢,當天到家后就梳理了這個知識點,現在結合Java 21線程池源碼落地到文檔,分享一些關于線程池的干貨,包括但不限于基本概念、執行流程、使用方法、最佳實踐和大廠八股文。

      ??我們下面認識一下什么是線程池。線程池從字面意思上來看就是一個基于池化技術管理同一組工作線程的池子,基本概念如下:是一種用于管理線程生命周期和任務執行的工具,它通過復用已有的工作線程,避免頻繁創建和銷毀工作線程的開銷,從而顯著提高應用程序的響應速度和吞吐量,提升資源利用率。通常,我們會使用 java.util.concurrent.ThreadPoolExecutor 或者 Spring 提供的 ThreadPoolExecutor 來創建和管理線程池。

      ??Java在使用線程執行程序時,需要調用操作系統內核的API創建一個內核線程,操作系統要為線程分配一系列的系統資源;當該Java線程被終止時,對應的內核線程也會被回收。因此,頻繁的創建和銷毀線程需要消耗大量資源。此外,由于CPU核數有限,大量的線程上下文切換會增加系統的性能開銷,無限制地創建線程還可能導致內存溢出。為此,Java在JDK1.5版本中引入了線程池。

      ??在項目開發過程中為什么使用線程池?我們先看看的ThreadPoolExecutor類中英文注釋是怎么描述的:

      Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, 
      due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, 
      including threads, consumed when executing a collection of tasks. Each {@code ThreadPoolExecutor} also maintains some basic statistics, 
      such as the number of completed tasks.
      

      ??中文意思大致就是線程池解決了兩個不同的問題:在執行大量異步任務時,它們一般通過復用線程降低每個任務的調用開銷來提高性能,同時線程池還提供了一種限制和管理執行任務時所消耗資源(包括線程)的方法。每個 {@code ThreadPoolExecutor} 還會維護一些基本的統計信息,例如已完成的任務數量。簡而言之,線程池能夠對線程進行統一分配、調優和監控:

      • 通過線程復用機制降低資源開銷。線程池維護了一個線程集合,盡可能復用線程完成不同的任務,避免了反反復復地創建和銷毀線程帶來的系統資源開銷。
      • 更有效的管理系統資源。使用線程池統一管理和監控系統資源,做到根據系統承載能力限制同時運行的線程數量,防止系統因創建過多線程而耗盡資源。還支持動態調整核心線程數。
      • 提高響應速度。由于線程被提前預熱,當有任務到達時立即被執行,因此顯著減少了創建線程這段時間的開銷,從而提高了系統的響應速度。據統計,創建一個線程大約耗時90微秒并占用1M內存

      ??鑒于以上線程池優勢,合理使用線程池可以幫助我們構建更加高效、穩定和易于維護的多線程應用程序。在業務系統開發過程中,線程池的兩個常見應用場景分別是快速響應用戶請求和高效處理批量任務。本文將全方位深入探討 Java 線程池,幫助讀者掌握線程池使用技巧和精通其原理。線程池源碼參考Java 21,具體版本是“21.0.6”。

      七個核心參數

      ??什么是任務執行器?它是實際執行任務的組件,包括執行任務的核心接口類 Executor和繼承了 Executor 的 ExecutorService 接口。Executor 框架有幾個關鍵類實現了 ExecutorService 接口:ThreadPoolExecutor 和 ScheduledThreadPoolExecutor、ForkJoinPool。Executor定義了一個簡單的 execute(Runnable command) 方法用于異步執行任務;而ExecutorService 接口繼承自 Executor,添加了更豐富的任務提交和生命周期管理輪子,如 submit(Runnable task)、submit(Callable task) 、isTerminated()、shutdown() 等。

      ??樓蘭胡楊在分析JUC線程池Executor框架體系時發現線程池的核心實現類是ThreadPoolExecutor,它是 Executor 框架中最重要的任務執行器實現,實現了 ExecutorService 接口。提供了一個可配置的線程池,用于執行異步任務。

      ??正所謂“先穿襪子后穿鞋,先當孫子后當爺”,如果要深入理解Java并發編程中的線程池,那么必須深入理解這個類的構造函數。我們來看一下ThreadPoolExecutor類中四個構造函數的源碼:

      public ThreadPoolExecutor(int corePoolSize,
                                int maximumPoolSize,
                                long keepAliveTime,
                                TimeUnit unit,
                                BlockingQueue<Runnable> workQueue) {
          this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
      }
      public ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<Runnable> workQueue,
                            ThreadFactory threadFactory) {
          this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);
      }
      public ThreadPoolExecutor(int corePoolSize,
                                int maximumPoolSize,
                                long keepAliveTime,
                                TimeUnit unit,
                                BlockingQueue<Runnable> workQueue,
                                RejectedExecutionHandler handler) {
          this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler);
      }
      public ThreadPoolExecutor(int corePoolSize,
                                int maximumPoolSize,
                                long keepAliveTime,
                                TimeUnit unit,
                                BlockingQueue<Runnable> workQueue,
                                ThreadFactory threadFactory,
                                RejectedExecutionHandler handler) {
          if (corePoolSize < 0 ||
              maximumPoolSize <= 0 ||
              maximumPoolSize < corePoolSize ||
              keepAliveTime < 0)
              throw new IllegalArgumentException();
          if (workQueue == null || threadFactory == null || handler == null)
              throw new NullPointerException();
          this.corePoolSize = corePoolSize;
          this.maximumPoolSize = maximumPoolSize;
          this.workQueue = workQueue;
          this.keepAliveTime = unit.toNanos(keepAliveTime);
          this.threadFactory = threadFactory;
          this.handler = handler;
          // 設置線程容器名稱
          String name = Objects.toIdentityString(this);
          // 創建線程容器,這就是線程池本尊,線程池的說法也是因為這個線程容器
          this.container = SharedThreadContainer.create(name);
      }
      

      ??SharedThreadContainer 是從 JDK 21 開始引入到源碼中的類,目的是支持進一步優化虛擬線程,用于管理共享線程容器。從源碼得知,ThreadPoolExecutor類提供了四個構造函數,事實上,前面三個構造器都是由第四個構造器衍生而來。下面基于入參最全的第四個構造函數解釋線程池中的七大核心參數。

      核心參數 業務含義
      int corePoolSize 核心線程數
      int maximumPoolSize 允許創建的最大線程數
      long keepAliveTime 空閑時間,即空閑線程在終止之前等待新任務的最長時間
      TimeUnit unit keepAliveTime的時間單位
      BlockingQueue workQueue 任務隊列
      ThreadFactory threadFactory 線程工廠
      RejectedExecutionHandler handler 拒絕策略

      ??下面對上述七大核心參數逐一詳細介紹。

      ??corePoolSize:線程池中核心線程(常駐線程)的個數。

      ??線程池被創建后,默認情況下其中并沒有任何線程,而是等待有任務到來才創建線程去執行當前任務。如果調用了 prestartAllCoreThreads() 或者 prestartCoreThread()方法,那么可以預創建線程,即在沒有任務到來之前就創建corePoolSize個或者一個線程。

      ??關于corePoolSize的值,如果設置的比較小,則會頻繁的創建和銷毀線程;如果設置的比較大,則浪費系統資源,實際工作中需要根據業務場景調整。如果設置corePoolSize為 0,則表示在沒有任務的時候,銷毀線程池。

      ??maximumPoolSize:線程池最大線程數,表示在線程池中最多允許創建多少個線程。它表示當核心線程已滿且任務隊列也滿時,線程池可以創建線程的最大個數。通常情況下,無界阻塞隊列可以視為無底洞,無論放入多少任務都填不滿,故maximumPoolSize對于使用了無界隊列的線程池而言就是花瓶,中看不中用。

      ??keepAliveTime:線程的空閑時間或者存活時間,即當線程游手好閑沒有任務執行時,繼續存活的時間。

      ??線程池的核心線程可以被回收嗎?ThreadPoolExecutor默認不回收核心線程,即 keepAliveTime 對它不起作用。但是提供了allowCoreThreadTimeOut(boolean value)方法,當傳的參數為true時,可以在無事可做時間達到線程存活時間后,回收核心線程,直到線程池中的線程數為0。

      ??unit:參數keepAliveTime的時間單位,默認值為TimeUnit.MILLISECONDS,對應TimeUnit類中的7種靜態屬性:

      TimeUnit.DAYS; //天 
      TimeUnit.HOURS; //小時 
      TimeUnit.MINUTES; //分鐘
      TimeUnit.SECONDS; //秒 
      TimeUnit.MILLISECONDS; //毫秒,默認值
      TimeUnit.MICROSECONDS; //微妙
      TimeUnit.NANOSECONDS; //納秒
      

      ??workQueue:任務隊列,采用阻塞隊列臨時存儲等待執行的任務,會對線程池的運行過程產生重大影響。

      ??當核心線程全部繁忙時,新提交的任務將存放在任務隊列中,等待被空閑線程執行。在ThreadPoolExecutor線程池的API文檔中,一共推薦了三種等待隊列,它們分別是ArrayBlockingQueue、synchronousQueue和默認的LinkedBlockingQueue等。

      ??threadFactory:線程工廠,主要用來創建線程。默認線程工廠是DefaultThreadFactory。

      ??handler:飽和策略,又稱拒絕策略,默認值為AbortPolicy。

      ??我們通過構造函數中的代碼 this.keepAliveTime = unit.toNanos(keepAliveTime)得知ThreadPoolExecutor的變量keepAliveTime等于構造函數中傳入的存活時間和單位對應的納秒數,所以,在函數ThreadPoolExecutor#getTask()中,直接基于納秒而非傳入的時間單位調用了workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)以從阻塞隊列獲取任務。如果這里感覺很晦澀,可以在閱讀《 JAVA JUC干貨之線程池實現原理和源碼詳解(下)》后再回頭了解這個知識點。

          /**
           * Timeout in nanoseconds for idle threads waiting for work.
           * Threads use this timeout when there are more than corePoolSize
           * present or if allowCoreThreadTimeOut. Otherwise they wait
           * forever for new work.
           */
          private volatile long keepAliveTime;
      

      線程工廠

      ??線程工廠有哪些作用? 負責生產線程去執行任務,通過線程工廠可以設置線程池中線程的屬性,包括名稱、優先級以及daemon類型等內容。同一個線程工廠創建的線程會歸屬于同一個線程組,擁有一樣的優先級,而且都不是守護線程。通過自定義的線程工廠可以給每個新建的線程設置一個具有業務含義、易于識別的線程名。

      ??線程優先級的作用是什么? 線程優先級用整數表示,取值范圍在 1-10 之間,默認優先級為 5。優先級表示當前線程被調度的權重,也就是說線程的優先級越高,被調度執行的可能性就越大。它會給線程調度器一個擇優執行線程的建議,至于是不是優先級越高的越先執行存在不確定性。它這樣設計的目的就是為了防止線程餓死。

      ??例1 通過引入com.google.guava包創建線程工廠。

      import com.google.common.util.concurrent.ThreadFactoryBuilder;
      // %d 表示從0開始增長的自然數
      ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
      

      ??例2 通過Java原汁原味的JUC包ThreadFactory創建線程工廠。

      // 自定義線程工廠
      ThreadFactory jucFactory = new ThreadFactory() {
          private final AtomicInteger mThreadNum = new AtomicInteger(1);
          @Override
          public Thread newThread(Runnable r) {
              // 為線程池創建線程
              Thread thread = new Thread(r);
              // 設置線程名稱
              thread.setName("Wiener-"  + mThreadNum.getAndIncrement());
              // 設置線程優先級
              thread.setPriority(Thread.MAX_PRIORITY);
              // 設置線程類型 (前臺/后臺線程)
              thread.setDaemon(false);
              return thread;
          }
      };
      

      拒絕策略

      ??假設線程數達到最大線程數maximumPoolSize且任務隊列已滿,如果繼續提交新任務,那么線程池必須采取一種拒絕策略處理該任務,在ThreadPoolExecutor中預定義了4種拒絕策略,下面結合源碼介紹。

      AbortPolicy

      ??ThreadPoolExecutor.AbortPolicy會拒絕執行任務并直接拋出RejectedExecutionException異常,是線程池的默認拒絕策略。源碼如下:

          /**
           * A handler for rejected tasks that throws a
           * {@link RejectedExecutionException}.
           *
           * This is the default handler for {@link ThreadPoolExecutor} and
           * {@link ScheduledThreadPoolExecutor}.
           */
          public static class AbortPolicy implements RejectedExecutionHandler {
              /**
               * Creates an {@code AbortPolicy}.
               */
              public AbortPolicy() { }
      
              /**
               * Always throws RejectedExecutionException.
               *
               * @param r the runnable task requested to be executed
               * @param e the executor attempting to execute this task
               * @throws RejectedExecutionException always
               */
              public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                  // 直接拋出RejectedExecutionException
                  throw new RejectedExecutionException("Task " + r.toString() +
                                                       " rejected from " +
                                                       e.toString());
              }
          }
      

      CallerRunsPolicy

      ??ThreadPoolExecutor.CallerRunsPolicy 由調用者所在的線程來執行新任務,而不是線程池中的線程執行。如果調用者線程已關閉,則拋棄任務。這種機制間接地對任務生產速率進行限流,有助于防止系統過載,同時確保沒有任務被粗暴地丟棄。

          /**
           * A handler for rejected tasks that runs the rejected task
           * directly in the calling thread of the {@code execute} method,
           * unless the executor has been shut down, in which case the task
           * is discarded.
           */
          public static class CallerRunsPolicy implements RejectedExecutionHandler {
              /**
               * Creates a {@code CallerRunsPolicy}.
               */
              public CallerRunsPolicy() { }
      
              /**
               * Executes task r in the caller's thread, unless the executor
               * has been shut down, in which case the task is discarded.
               *
               * @param r the runnable task requested to be executed
               * @param e the executor attempting to execute this task
               */
              public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                  if (!e.isShutdown()) {
                      r.run(); // 直接由調用者線程執行任務【r】,而不是線程池中的線程執行
                  }
              }
          }
      

      DiscardOldestPolicy

      ??ThreadPoolExecutor.DiscardOldestPolicy丟棄阻塞隊列中最靠前的任務,然后嘗試執行新任務。

      ??ThreadPoolExecutor.DiscardOldestPolicy先將阻塞隊列中的頭元素出隊拋棄,再嘗試提交任務。如果此時阻塞隊列使用PriorityBlockingQueue優先級隊列,將會導致最高優先級的任務被拋棄,因此不建議將該種策略配合優先級隊列使用。

      DiscardPolicy

      ??ThreadPoolExecutor.DiscardPolicy直接丟棄任務,但是不拋出異常。源碼如下:

          /**
           * A handler for rejected tasks that silently discards the
           * rejected task.
           */
          public static class DiscardPolicy implements RejectedExecutionHandler {
              /**
               * Creates a {@code DiscardPolicy}.
               */
              public DiscardPolicy() { }
      
              /**
               * Does nothing, which has the effect of discarding task r.
               *
               * @param r the runnable task requested to be executed
               * @param e the executor attempting to execute this task
               */
              public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
              }
          }
      

      自定義拒絕策略

      ??我們也可以根據業務場景實現RejectedExecutionHandler中函數rejectedExecution,創建我們自己的飽和策略,如記錄日志或持久化存儲不能處理的任務。

      ??下面是一個簡單的例子,展示如何實現一個自定義的拒絕策略。這個策略會在任務被拒絕時打印一條消息,并記錄被拒絕的任務信息,同時支持把此任務持久化到Redis。

      public class RejectionImpl implements RejectedExecutionHandler {
          @Override
          public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
              // 這里寫我們自定義的拒絕策略
              System.out.println("被拒絕任務是 " + r.toString());
              System.out.println("把此任務持久化到Redis");
          }
      }
      

      ??在創建線程池的時候,把 new RejectionImpl() 傳入即可,下文會給出實戰案例。自定義拒絕策略通常可以做兩件事:

      • 記錄日志,以便追溯問題。
      • 通知告警,搖相關人員解決問題。

      ??面試官:你在實際工作中/項目中,使用的是哪一種拒絕策略?

      ??參考答案:如果不知道怎么回答,建議回答自定義拒絕策略,因為它比較靈活,可以設置想設置的邏輯,我在里面呢,首先可以把錯誤記錄下來,其次可以給任務隊列發一個郵件,或者發一個 MQ(消息不丟失)。

      ??面試官:如果不允許丟棄任務,應該選擇哪種拒絕策略?

      ??參考答案:如果不擔心阻塞主線程,可以選擇CallerRunsPolicy。更絲滑的方案是基于任務持久化自定義拒絕策略,持久化方案包括但不限于:

      • 把任務存儲到Redis中。
      • 把任務存儲到 MySQL 數據庫中。
      • 把任務提交到消息隊列中。

      ??這里以方案一為例,簡單介紹一下實現邏輯:

      ??步驟一 使用前面剛剛自定義的拒絕策略RejectionImpl,將線程池需要拒絕處理的任務持久化到Redis中。

      ??步驟二 擴展LinkedBlockingQueue實現一個自定義阻塞隊列。重寫取任務的邏輯take()或者poll()方法,優先從Redis中讀取最早存儲的任務,Redis中無任務時再從線程池阻塞隊列中取任務。

      import java.util.concurrent.LinkedBlockingQueue;
      
      /**
       * @Author Wiener
       * @Date 2025-04-17
       * @Description: 自定義阻塞隊列
       */
      public class CustomBlockingQueue<E> extends LinkedBlockingQueue<E> {
      
          @Override
          public E take() throws InterruptedException {
              E x;
              if (redis中有任務?) {
                  // 從Redis讀取最早放入的任務
              } else {
                  // 從阻塞隊列拿任務
                  x = super.take();
              }
              // 返回拿到的任務
              return x;
          }
      }
      

      監控線程池運行狀態

      ??可以使用ThreadPoolExecutor以下方法實時監控線程池運行狀態:

      getTaskCount() Returns the approximate total number of tasks that have ever been scheduled for execution.

      getCompletedTaskCount() Returns the approximate total number of tasks that have completed execution. 返回結果少于getTaskCount()。

      getLargestPoolSize() Returns the largest number of threads that have ever simultaneously been in the pool. 返回結果小于等于maximumPoolSize

      getPoolSize() Returns the current number of threads in the pool.

      getActiveCount() Returns the approximate number of threads that are actively executing tasks.#

      關閉和動態調整線程池|done

      ??在應用程序結束時,要確保線程池能夠被優雅地關閉。ThreadPoolExecutor提供了兩個關閉線程池的輪子:

      ??shutdown(): 等所有阻塞隊列中的任務都執行完后才關閉線程池,但再也不會接收新的任務。

      ??shutdownNow(): 立即嘗試打斷正在執行的任務,并且清空阻塞隊列,返回尚未執行的任務。

      ??它們的原理都是遍歷線程池的工作線程,然后逐個調用線程的interrupt方法來中斷線程,所以無法響應中斷的任務可能永遠無法被停止。

      ??二者區別:shutdown函數將平緩的執行關閉過程,拒絕新提交的任務,完成所有運行中的任務,同時等待任務隊列中的任務執行完成。shutdownNow方法將粗暴的執行關閉過程,它將嘗試取消所有運行中的任務,并且無腦式地清空任務隊列。

      ??只要調用了這兩個關閉方法中的任意一個,isShutdown函數就會返回true,當所有的任務都已關閉后,才表示線程池關閉成功,這時調用isTerminated方法會返回true。至于應該調用哪一種方法來關閉線程池,應該由提交到線程池的任務特性決定,通常調用shutdown方法來關閉線程池,如果任務不一定要執行完,則可以調用shutdownNow方法。

      ??ThreadPoolExecutor提供了動態調整線程池容量大小的方法:

      • setCorePoolSize 設置核心線程池大小。
      • setMaximumPoolSize 動態調整線程池最大線程數maximumPoolSize。

      ??當從小到大調整上述兩個參數時,ThreadPoolExecutor實時調整線程池配置,可能導致立即創建新的線程來執行任務。

      線程池的缺點

      ??Java線程池雖然有很多優點,如在綜述中提到的高效管理系統資源、減少資源消耗和提高響應速度等,但也存在一些缺點和需要格外留意的地方:

      復雜的錯誤處理:在線程池中運行的任務如果拋出未捕獲異常,可能會導致線程終止,進而影響整個線程池的工作效率。

      資源耗盡:如果線程池配置得過小,當有大量并發請求時,可能導致請求排隊時間過長甚至拒絕服務;相反,若線程池過大,則會消耗大量系統資源(如內存),還可能引起頻繁的垃圾回收(GC)。

      線程饑餓:在某些情況下,比如線程池中的線程都在執行長時間運行的任務,那么新來的短期任務就可能會長時間等待,造成線程饑餓現象。

      死鎖風險:如果線程池配置不當或者任務設計不合理,容易引發死鎖問題。例如,線程池中的所有線程都在等待另一個任務完成,而這個任務又在等待線程池中的空閑線程,這樣就會形成死鎖。

      任務丟失:如果線程池的隊列滿了且設置了拒絕策略為丟棄任務,那么新的任務可能會直接被丟棄。

      ??為了克服上述缺點,合理地設置線程池參數、選擇合適的線程池類型(如CachedThreadPool, SingleThreadExecutor等)以及正確實現任務邏輯是非常關鍵的。同時,也可以通過監控線程池的狀態來動態調整其配置。

      提交任務

      ??既然談到線程池如何執行任務,就必須先談談如何提交任務。我們在線程池中可以使用兩種方式提交任務,一種是execute,另一種是submit。這兩種方式的區別如下:


      兩種提交任務的方式
      1. 任務類型

        • execute只支持提交Runnable類型的任務。
        • submit提交的任務類型既能是Runnable也能是Callable。
      2. 執行結果

        • execute沒有返回值,故無法獲取執行結果。
        • submit可以獲取執行結果。它返回一個Future類型的對象,通過這個對象可以拿到任務執行結果和任務是否執行成功。如Future<Object> futureResult = executor.submit(task)
      3. 異常處理

        • execute會直接拋出執行任務時遇到的異常,可以使用try catch來捕獲,這一點和普通線程的處理方式完全一致。
        • submit函數會吃掉異常,但是如果調用Future的get方法,異常將重新拋出。

      ??雖然兩者提交任務的入參類型有差異,但是最終處理任務的方法是相同的,都是ThreadPoolExecutor類的函數execute。總之,如果不需要拿到任務執行結果,直接調用execute會提高性能。

      ??在實際業務場景中,Future和Callable基本是成對出現的,Callable負責封裝執行結果,Future負責獲取結果。Future可以拿到異步執行任務的結果,不過,調用Future.get方法會導致主線程阻塞,直到Callable任務執行完成。

      結束語

      ??至此,已經介紹完線程池基本概念,關于線程池實現原理和源碼詳解將在下一篇《JAVA JUC干貨之線程池實現原理和源碼詳解(下)》中展開。預祝各位讀者在工作中能夠迅速而準確地處理線程池相關需求,就像運斤成風一樣。

      ??在編程這個復雜嚴峻的環境中,請活得優雅坦然:也許你的錢包空空如也,也許你的工作不夠好,也許你正處在困境中,也許你被情所棄。不論什么原因,請你在出門時,一定要把自己打扮地清清爽爽,昂起頭,挺起胸,面帶微笑,從容自若地面對生活和面對工作。人生就像蒲公英,沒事盡量少吹風;只要你自己真正撐起來了一片天地,別人無論如何是壓不垮你的,內心的強大才是真正的強大。

      Reference

      posted @ 2025-05-30 09:12  樓蘭胡楊  閱讀(325)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 东京热加勒比无码少妇| 国产精品一区免费在线看| 伊金霍洛旗| 好吊视频专区一区二区三区| 深夜精品免费在线观看| 亚洲成人高清av在线| 成人性生交片无码免费看| 亚洲中文字幕精品久久久久久动漫| 农民人伦一区二区三区| 欧美裸体xxxx极品| 成人一区二区人妻不卡视频| 亚洲午夜成人精品电影在线观看 | 国产精品国产高清国产专区| 制服丝袜美腿一区二区| 麻豆国产AV剧情偷闻女邻居内裤| 四虎国产精品免费久久| 国产日韩精品欧美一区灰| 国产绿帽在线视频看| 欧美叉叉叉bbb网站| 国产一区二区丰满熟女人妻| 精品中文字幕人妻一二| 苍山县| 亚洲色婷婷一区二区三区| 国产成人综合95精品视频| 国产精品久久久一区二区三区| 性欧洲大肥性欧洲大肥女| 国内自拍偷拍福利视频看看| 她也色tayese在线视频| 成人永久性免费在线视频| 人妻精品动漫H无码中字| 日韩美av一区二区三区| 无码国产偷倩在线播放| 国产综合视频一区二区三区| 国产精品爽爽v在线观看无码 | 中国CHINA体内裑精亚洲日本| 人妻少妇精品无码专区二区| japanese无码中文字幕| 综合欧美视频一区二区三区| 蜜臀一区二区三区精品免费| 依依成人精品视频在线观看| 亚洲精品色国语对白在线|