日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

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

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

一:前言

一個問題引出的學(xué)習(xí)筆記
并發(fā)類庫提供的線程池實現(xiàn)有哪些?
其實Executors已經(jīng)為我們封裝好了 4 種常見的功能線程池,如下:

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

那么接下來就復(fù)習(xí)一波線程和線程池

二:線程

1:關(guān)于線程的理解

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

2:線程的聲明周期

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

3:單線程和多線程

三:線程池

1:線程池從何處而來

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

2:線程池的好處

  • (1) 降低資源消耗。 通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。
  • (2) 提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時,任務(wù)可以不需要等到線程創(chuàng)建就能立即執(zhí)行。
  • (3) 提高線程的可管理性。線程是稀缺資源,如果無限制的創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,使用線程池可以進(jìn)行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。

3:如何實現(xiàn)線程池

那么,我們應(yīng)該如何創(chuàng)建一個線程池那?Java中已經(jīng)提供了創(chuàng)建線程池的一個類:Executor類,而我們創(chuàng)建時,一般使用它的子類:ThreadPoolExecutor.
線程池的真正實現(xiàn)類是 ThreadPoolExecutor,其構(gòu)造方法有如下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:線程池的使用流程

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

5:線程池的工作原理

6:線程池的重要參數(shù)解讀

(1):任務(wù)隊列

(2):線程工廠(threadFactory)

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

(3):拒絕策略(handler)

7:功能性線程池

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

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

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

創(chuàng)建的源碼:

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); }
  • 特點:只有核心線程,線程數(shù)量固定,執(zhí)行完立即回收,任務(wù)隊列為鏈表結(jié)構(gòu)的有界隊列。
  • 應(yīng)用場景:控制線程最大并發(fā)數(shù)。
  • 使用實例:
// 1. 創(chuàng)建定長線程池對象 & 設(shè)置線程池線程數(shù)量固定為3 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); // 2. 創(chuàng)建好Runnable類線程對象 & 需執(zhí)行的任務(wù) Runnable task =new Runnable(){public void run() {System.out.println("執(zhí)行任務(wù)啦");} }; // 3. 向線程池提交任務(wù) fixedThreadPool.execute(task);

(2): newWorkStealingPool


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

(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 個核心線程,無非核心線程,執(zhí)行完立即回收,任務(wù)隊列為鏈表結(jié)構(gòu)的有界隊列。
應(yīng)用場景:不適合并發(fā)但可能引起 IO 阻塞性及影響 UI 線程響應(yīng)的操作,如數(shù)據(jù)庫操作、文件操作等。
使用實例:

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 (可緩存的線程池)

創(chuàng)建方法的源碼:

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

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

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

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

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

創(chuàng)建方法的源碼: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); }

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

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

參考自這篇博客

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。