日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线程与线程池(一条龙详解)

發布時間:2023/12/4 编程问答 98 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线程与线程池(一条龙详解) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一:前言

一個問題引出的學習筆記
并發類庫提供的線程池實現有哪些?
其實Executors已經為我們封裝好了 4 種常見的功能線程池,如下:

  • 定長線程池(FixedThreadPool)
  • 定時線程池(ScheduledThreadPool )
  • 可緩存線程池(CachedThreadPool)
  • 單線程化線程池(SingleThreadExecutor)

那么接下來就復習一波線程和線程池

二:線程

1:關于線程的理解

  • 自我理解:(這是在javaweb中的文件上傳部分 實際用到的線程 來幫助理解線程)
    一個線程就是一條執行路徑 ,實際例子當中 我們請求一個頁面如果需要很長的時間的話,這時候我們需要設置線程來執行 請求消息中的代碼,然后再寫一個代碼先顯示出請求等待的信息
  • 官方解讀:
    線程,程序執行流的最小執行單位,是行程中的實際運作單位,經常容易和進程這個概念混淆。那么,線程和進程究竟有什么區別呢?首先,進程是一個動態的過程,是一個活動的實體。簡單來說,一個應用程序的運行就可以被看做是一個進程,而線程,是運行中的實際的任務執行者。可以說,進程中包含了多個可以同時運行的線程。

2:線程的聲明周期

線程的生命周期,線程的生命周期可以利用以下的圖解來更好的理解:

3:單線程和多線程

三:線程池

1:線程池從何處而來

  • 在一個應用程序中,我們需要多次使用線程,也就意味著,我們需要多次創建并銷毀線程。而創建并銷毀線程的過程勢必會消耗內存。而在Java中,內存資源是及其寶貴的,所以,我們就提出了線程池的概念
    線程池:Java中開辟出了一種管理線程的概念,這個概念叫做線程池,從概念以及應用場景中,我們可以看出,線程池的好處,就是可以方便的管理線程,也可以減少內存的消耗。

2:線程池的好處

  • (1) 降低資源消耗。 通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。
  • (2) 提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。
  • (3) 提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。

3:如何實現線程池

那么,我們應該如何創建一個線程池那?Java中已經提供了創建線程池的一個類:Executor類,而我們創建時,一般使用它的子類:ThreadPoolExecutor.
線程池的真正實現類是 ThreadPoolExecutor,其構造方法有如下4種:

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; }

4:線程池的使用流程

// 創建線程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,TimeUnit.SECONDS,sPoolWorkQueue,sThreadFactory); // 向線程池提交任務 threadPool.execute(new Runnable() {@Overridepublic void run() {... // 線程執行的任務} }); // 關閉線程池 threadPool.shutdown(); // 設置線程池的狀態為SHUTDOWN,然后中斷所有沒有正在執行任務的線程 threadPool.shutdownNow(); // 設置線程池的狀態為 STOP,然后嘗試停止所有的正在執行或暫停任務的線程,并返回等待執行任務的列表

5:線程池的工作原理

6:線程池的重要參數解讀

(1):任務隊列

(2):線程工廠(threadFactory)

線程工廠指定創建線程的方式,需要實現 ThreadFactory 接口,并實現 newThread(Runnable r) 方法。該參數可以不用指定,Executors 框架已經為我們實現了一個默認的線程工廠:

(3):拒絕策略(handler)

7:功能性線程池

嫌上面使用線程池的方法太麻煩?其實Executors已經為我們封裝好了 4 種常見的功能線程池,如下:

  • 定長線程池(FixedThreadPool)
  • 定時線程池(ScheduledThreadPool )
  • 可緩存線程池(CachedThreadPool)
  • 單線程化線程池(SingleThreadExecutor)
  • newWorkStealingPool

(1): newFixedThreadPool (固定數量的線程池)

創建的源碼:

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory); }
  • 特點:只有核心線程,線程數量固定,執行完立即回收,任務隊列為鏈表結構的有界隊列。
  • 應用場景:控制線程最大并發數。
  • 使用實例:
// 1. 創建定長線程池對象 & 設置線程池線程數量固定為3 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); // 2. 創建好Runnable類線程對象 & 需執行的任務 Runnable task =new Runnable(){public void run() {System.out.println("執行任務啦");} }; // 3. 向線程池提交任務 fixedThreadPool.execute(task);

(2): newWorkStealingPool


這個線程池的特性從名字就可以看出 Stealing,會竊取任務。
每個線程都有自己的雙端隊列,當自己隊列的任務處理完畢之后,會去別的線程的任務隊列尾部拿任務來執行,加快任務的執行速率。
至于 ForkJoin 的話,就是分而治之,把大任務分解成一個個小任務,然后分配執行之后再總和結果,

(3): newSingleThreadExecutor (單線程池)

public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory)); }

特點:只有 1 個核心線程,無非核心線程,執行完立即回收,任務隊列為鏈表結構的有界隊列。
應用場景:不適合并發但可能引起 IO 阻塞性及影響 UI 線程響應的操作,如數據庫操作、文件操作等。
使用實例:

public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory)); }

(4):newCachedThreadPool (可緩存的線程池)

創建方法的源碼:

public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>()); } public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),threadFactory); }

特點:無核心線程,非核心線程數量無限,執行完閑置 60s 后回收,任務隊列為不存儲元素的阻塞隊列。
應用場景:執行大量、耗時少的任務。

所以它適合用在短時間內有大量短任務的場景。如果暫無可用線程,那么來個任務就會新啟一個線程去執行這個任務,快速響應任務。
但是如果任務的時間很長,那存在的線程就很多,上下文切換就很頻繁,切換的消耗就很明顯,并且存在太多線程在內存中,也有 OOM 的風險。
使用示例:

// 1. 創建可緩存線程池對象 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); // 2. 創建好Runnable類線程對象 & 需執行的任務 Runnable task =new Runnable(){public void run() {System.out.println("執行任務啦");} }; // 3. 向線程池提交任務 cachedThreadPool.execute(task);

(5): newScheduledThreadPool(定時線程池)

創建方法的源碼:private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize); } public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue()); }public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); } public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue(), threadFactory); }

特點:核心線程數量固定,非核心線程數量無限,執行完閑置 10ms 后回收,任務隊列為延時阻塞隊列。
應用場景:執行定時或周期性的任務。
使用示例:

/ 1. 創建 定時線程池對象 & 設置線程池線程數量固定為5 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); // 2. 創建好Runnable類線程對象 & 需執行的任務 Runnable task =new Runnable(){public void run() {System.out.println("執行任務啦");} }; // 3. 向線程池提交任務 scheduledThreadPool.schedule(task, 1, TimeUnit.SECONDS); // 延遲1s后執行任務 scheduledThreadPool.scheduleAtFixedRate(task,10,1000,TimeUnit.MILLISECONDS);// 延遲10ms后、每隔1000ms執行任務

參考自這篇博客

總結

以上是生活随笔為你收集整理的线程与线程池(一条龙详解)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。