国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

【從0到1學習Java線程池】Java線程池的簡介以及使用

2019-11-06 09:11:06
字體:
來源:轉載
供稿:網友

這是【從0到1學習java線程池】系列文章的第 壹 篇,該系列文章總共三篇,介紹了 Java 線程池的使用以及原理,并且最后會實現一個基本的線程池。本篇文章主要介紹了 Java 線程池以及它的使用。

線程池是什么?

線程池用于多線程處理中,它可以根據系統的情況,可以有效控制線程執行的數量,優化運行效果。線程池做的工作主要是控制運行的線程的數量,處理過程中將任務放入隊列,然后在線程創建后啟動這些任務,如果線程數量超過了最大數量超出數量的線程排隊等候,等其它線程執行完畢,再從隊列中取出任務來執行。

線程池的作用

在面向對象的編程過程中,創建對象和銷毀對象是非常消耗時間和資源的。因此想要最小化這種消耗的一種思想就是『池化資源』。線程池就是這樣的一種思想。我們通過重用線程池中的資源來減少創建和銷毀線程所需要耗費的時間和資源。

線程池的一個作用是創建和銷毀線程的次數,每個工作線程可以多次使用;另一個作用是可根據系統情況調整執行的線程數量,防止消耗過多內存。另外,通過線程池,能有效的控制線程的最大并發數,提高系統資源利用率,同時避免過多的資源競爭,避免堵塞。

線程池的優點總結如下幾個方面:

線程復用控制最大并發數管理線程

線程池的組成

一般的線程池主要分為以下4個組成部分:

線程池管理器:用于創建并管理線程池工作線程:線程池中的線程任務接口:每個任務必須實現的接口,用于工作線程調度其運行任務隊列:用于存放待處理的任務,提供一種緩沖機制

線程池的常見應用場景

許多服務器應用常常需要處理大量而短小的請求(例如,Web 服務器,數據庫服務器等等),通常它們收到的請求數量很大,一個簡單的模型是,當服務器收到來自遠程的請求時,為每一個請求開啟一個線程,在請求完畢之后再對線程進行銷毀。這樣處理帶來的問題是,創建和銷毀線程所消耗的時間往往比任務本身所需消耗的資源要大得多。那么應該怎么辦呢?

線程池為線程生命周期開銷問題和資源不足問題提供了解決方案。我們可以通過線程池做到線程復用,不需要頻繁的創建和銷毀線程,讓線程池中的線程一直存在于線程池中,然后線程從任務隊列中取得任務來執行。而且這樣做的另一個好處有,通過適當地調整線程池中的線程數目,也就是當請求的數目超過某個閾值時,就強制其它任何新到的請求一直等待,直到獲得一個線程來處理為止,從而可以防止資源不足。

Java線程池的簡介

Java中提供了實現線程池的框架Executor,并且提供了許多種類的線程池,接下來的文章中將會做詳細介紹。

Java線程池框架

Java中的線程池是通過Executor框架實現的,該框架中用到了ExecutorExecutors,ExecutorService,ThreadPoolExecutorCallableFuture、FutureTask這幾個類。

Executor:所有線程池的接口,只有一個方法Executors:Executor 的工廠類,提供了創建各種不同線程池的方法,返回的線程池都實現了ExecutorService 接口ThreadPoolExecutor:線程池的具體實現類,一般所有的線程池都是基于這個類實現的

其中ThreadPoolExecutor的構造方法如下:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);}

其中:

corePoolSize:線程池的核心線程數,線程池中運行的線程數也永遠不會超過 corePoolSize 個,默認情況下會永遠存活maximumPoolSize:線程池中允許的最大線程數keepAliveTime:空閑線程結束的超時時間unit:是一個枚舉,它表示的是 keepAliveTime 的單位workQueue:工作隊列,用于任務的存放

Java線程池的工作過程

Java線程池的工作過程如下:

線程池剛創建時,里面沒有一個線程。任務隊列是作為參數傳進來的。不過,就算隊列里面有任務,線程池也不會馬上執行它們。當調用 execute() 方法添加一個任務時,線程池會做如下判斷:如果正在運行的線程數量小于 corePoolSize,那么馬上創建線程運行這個任務;如果正在運行的線程數量大于或等于 corePoolSize,那么將這個任務放入隊列;如果這時候隊列滿了,而且正在運行的線程數量小于 maximumPoolSize,那么還是要創建非核心線程立刻運行這個任務;如果隊列滿了,而且正在運行的線程數量大于或等于 maximumPoolSize,那么線程池會拋出異常RejectExecutionException。當一個線程完成任務時,它會從隊列中取下一個任務來執行。當一個線程無事可做,超過一定的時間(keepAliveTime)時,線程池會判斷,如果當前運行的線程數大于 corePoolSize,那么這個線程就被停掉。所以線程池的所有任務完成后,它最終會收縮到 corePoolSize 的大小。

常見的Java線程池

生成線程池使用的是Executors的工廠方法,以下是常見的 Java 線程池:

SingleThreadExecutor

SingleThreadExecutor是單個線程的線程池,即線程池中每次只有一個線程在運行,單線程串行執行任務。如果這個唯一的線程因為異常結束,那么會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行。

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

FixedThreadPool

FixedThreadPool是固定數量的線程池,只有核心線程,每提交一個任務就是一個線程,直到達到線程池的最大數量,然后后面進入等待隊列,直到前面的任務完成才繼續執行。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那么線程池會補充一個新線程。

public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());}

CachedThreadPool

CachedThreadPool是可緩存線程池。如果線程池的大小超過了處理任務所需要的線程,那么就會回收部分空閑(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(或者說JVM)能夠創建的最大線程大小。其中,SynchronousQueue是一個是緩沖區為1的阻塞隊列。

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

ScheduledThreadPool

ScheduledThreadPool是核心線程池固定,大小無限制的線程池,支持定時和周期性的執行線程。創建一個周期性執行任務的線程池。如果閑置,非核心線程池會在DEFAULT_KEEPALIVEMILLIS時間內回收。

public static ExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPool(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue());}

Java 線程池的創建和使用

我們可以通過Executors的工廠方法來創建一個線程池。但是我們該如何讓線程池執行任務呢?

線程池最常用的提交任務的方法有兩種:

execute:

ExecutorService.execute(Runnable runable);

submit:

FutureTask task = ExecutorService.submit(Runnable runnable);FutureTask<T> task = ExecutorService.submit(Runnable runnable,T Result);FutureTask<T> task = ExecutorService.submit(Callable<T> callable);

可以看出submit開啟的是有返回結果的任務,會返回一個FutureTask對象,這樣就能通過get()方法得到結果。submit最終調用的也是execute(Runnable runable),submit只是將Callable對象或Runnable封裝成一個FutureTask對象,因為FutureTask是個Runnable,所以可以在execute中執行。

下面的示例代碼演示了如何創建一個線程池,并且使用它管理線程:

public class MyThread extends Thread { @Override public void run() { System.out.PRintln(Thread.currentThread().getName() + " is running."); }}public class TestSingleThreadExecutor { public static void main(String[] args) { //創建一個可重用固定線程數的線程池 ExecutorService pool = Executors.newFixedThreadPool(2); //創建實現了Runnable接口對象 Thread tt1 = new MyThread(); Thread tt2 = new MyThread(); Thread tt3 = new MyThread(); Thread tt4 = new MyThread(); Thread tt5 = new MyThread(); //將線程放入池中并執行 pool.execute(tt1); pool.execute(tt2); pool.execute(tt3); pool.execute(tt4); pool.execute(tt5); //關閉 pool.shutdown(); }}

運行結果:

pool-1-thread-1 is running.pool-1-thread-2 is running.pool-1-thread-1 is running.pool-1-thread-2 is running.pool-1-thread-1 is running.

本文的版權歸作者 羅遠航 所有,采用 Attribution-NonCommercial 3.0 License。任何人可以進行轉載、分享,但不可在未經允許的情況下用于商業用途;轉載請注明出處。感謝配合!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 关岭| 庆安县| 密山市| 北辰区| 涞源县| 改则县| 沂水县| 子洲县| 桦甸市| 郯城县| 汝南县| 信宜市| 永顺县| 仪征市| 红桥区| 于田县| 仙游县| 浮梁县| 溧水县| 同德县| 太和县| 安西县| 云和县| 张家界市| 巴马| 盘锦市| 鱼台县| 蒲城县| 福泉市| 麦盖提县| 龙游县| 多伦县| 巴林右旗| 镶黄旗| 墨竹工卡县| 攀枝花市| 溧水县| 洪江市| 浪卡子县| 赤水市| 鹤山市|