Java多執行緒-執行緒池Executors
概覽
通過上一篇對ThreadPoolExecutor的構造方法分析可以感受到,通過ThreadPoolExecutor來建立執行緒池是比較複雜的,引數比較多,考慮因素也多。
因此java自己提供了一個工廠類Executors,裡面提供了一些方法,用來建立常用的幾種ThreadPoolExecutor執行緒池。
下面是方法概覽:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0 L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
分析
FixedThreadPool
FixedThreadPool呼叫的是ThreadPoolExecutor的構造方法。有下面兩種使用方式:
//不帶工廠的
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);
}
通過對ThreadPoolExecutor構造引數的分析可以看出來,這個執行緒池的最大執行緒數就是核心執行緒數,也就是沒有非核心執行緒的存在。這些執行緒都是核心執行緒,即使在閒置狀態也不會被回收,除非執行緒池關閉了,所以超時機制並沒有用。他的任務佇列是無界的LinkedBlockingQueue,因此超過核心執行緒數量的任務會放在佇列中排隊。
這樣的執行緒池優點很明顯,只會建立固定數量的執行緒,然後這些執行緒一直存活重用,不會有額外的建立和銷燬執行緒的開銷,能更快的執行任務。
測試
ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable myRunnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 6; i++) {
executor.execute(myRunnable);
}
建立一個固定大小為2的FixedThreadPool,然後新增6個任務,輸出是:
pool-1-thread-2 run time: 1493863106021
pool-1-thread-1 run time: 1493863106021
pool-1-thread-2 run time: 1493863108022
pool-1-thread-1 run time: 1493863108022
pool-1-thread-1 run time: 1493863110026
pool-1-thread-2 run time: 1493863110027
可以看到這個執行緒池只會建立2個執行緒,其他的都在排隊。
執行緒工廠
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2,new MyFactory());
Runnable myRunnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 6; i++) {
executor.execute(myRunnable);
}
}
static class MyFactory implements ThreadFactory{
@Override
public Thread newThread(@NonNull Runnable r) {
Thread thread = new Thread(r);
thread.setName("哈哈"+ UUID.randomUUID().toString().substring(0,3));
return thread;
}
}
建立一個工廠,自定義設定執行緒名字,然後在newFixedThreadPool時傳入工廠,看輸出
哈哈fea run time: 1493863498244
哈哈491 run time: 1493863498244
哈哈fea run time: 1493863500250
哈哈491 run time: 1493863500250
哈哈fea run time: 1493863502253
哈哈491 run time: 1493863502253
下面的工廠引數都是這樣,就不在寫了。
CachedThreadPool
CachedThreadPool也是用的ThreadPoolExecutor的構造方法
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1, threadFactory));
}
分析這個引數可以看出,這個執行緒池沒有核心執行緒,所有的執行緒都會在限制60秒後被回收。而且最大執行緒數為Integer.MAX_VALUE,相當於無限大。因為任務佇列是SynchronousQueue,不會儲存任何任務,所以當有新任務時,如果當前執行緒都在活動著,就會新建一個執行緒來執行任務。
這樣的執行緒池的特點就是,適合執行大量的耗時短的任務。而且當所有任務執行完後,閒置超過60秒就會全部回收,這是執行緒池裡就沒有任何執行緒,不會佔用系統資源。
測試
ExecutorService executor = Executors.newCachedThreadPool();
Runnable myRunnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 3; i++) {
executor.execute(myRunnable);
}
Thread.sleep(30000);
System.out.println("睡眠30秒後");
for (int i = 0; i < 3; i++) {
executor.execute(myRunnable);
}
Thread.sleep(65000);
System.out.println("再睡眠65秒後");
for (int i = 0; i < 3; i++) {
executor.execute(myRunnable);
}
先執行三個任務,30秒後再新增3個任務,再過65秒再新增3個任務。
pool-1-thread-1 run time: 1493864065635
pool-1-thread-2 run time: 1493864065635
pool-1-thread-3 run time: 1493864065639
睡眠30秒後
pool-1-thread-3 run time: 1493864095637
pool-1-thread-2 run time: 1493864095637
pool-1-thread-1 run time: 1493864095637
再睡眠65秒後
pool-1-thread-5 run time: 1493864160643
pool-1-thread-4 run time: 1493864160643
pool-1-thread-6 run time: 1493864160643
可以看到一開始建立了3個執行緒,30秒後重用了這三個執行緒。但是再過65秒後,者三個執行緒就因為超時被回收了,所以新建了三個執行緒。
SingleThreadExecutor
SingleThreadExecutor使用new FinalizableDelegatedExecutorService
來建立執行緒池。但是其實通過一個委託呼叫了ThreadPoolExecutor的構造方法
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));
}
從ThreadPoolExecutor的構造引數依然可以看出,這個執行緒池僅有一個核心執行緒,其他的任務都在任務佇列中排隊。
這樣的執行緒池會讓所有的任務都在同一個執行緒中執行,避免的同步問題。
測試
ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable myRunnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 3; i++) {
executor.execute(myRunnable);
}
Thread.sleep(65000);
System.out.println("睡眠65秒後");
for (int i = 0; i < 3; i++) {
executor.execute(myRunnable);
}
pool-1-thread-1 run time: 1493864476076
pool-1-thread-1 run time: 1493864478078
pool-1-thread-1 run time: 1493864480082
睡眠65秒後
pool-1-thread-1 run time: 1493864541080
pool-1-thread-1 run time: 1493864543083
pool-1-thread-1 run time: 1493864545087
自始至終都只有一個執行緒。而且不會被回收。
ScheduledThreadPool
ScheduledThreadPool使用new ScheduledThreadPoolExecutor
來建立
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
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);
}
可以看到,這個執行緒池的核心執行緒數是固定的,但是匯流排程數是無限的,然而因為DelayedWorkQueue是個無界佇列,所以這個值沒有意義,超過核心執行緒的任務都會放在佇列中。
ScheduledThreadPoolExecutor主要是用來執行定時任務和有周期性的重複任務。
這裡就舉個不恰當的例子,不是ScheduledThreadPoolExecutor的用法
ExecutorService executor = Executors.newScheduledThreadPool(3);
Runnable myRunnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 6; i++) {
executor.execute(myRunnable);
}
pool-1-thread-3 run time: 1493866372444
pool-1-thread-1 run time: 1493866372444
pool-1-thread-2 run time: 1493866372444
pool-1-thread-2 run time: 1493866374450
pool-1-thread-1 run time: 1493866374450
pool-1-thread-3 run time: 1493866374450
設定的是3,就只會建立3個執行緒。
相關推薦
跟我學Java多線程——線程池與堵塞隊列
信號 線程的創建 margin cit rect weight offer 成功 rain 前言 上一篇文章中我們將ThreadPoolExecutor進行了深入的學習和介紹,實際上我們在項目中應用的時候非常少有直接應用ThreadPoolExecutor來
Java多線程-線程池ThreadPoolExecutor構造方法和規則
解決 $1 核心 keepaliv 狀態 被拒絕 live link 限時 為什麽用線程池 博客地址 http://blog.csdn.net/qq_25806863 原文地址 http://blog.csdn.net/qq_25806863/article/details
Java 多執行緒池ThreadPoolExecutor解析及Executors類中提供的靜態方法來建立執行緒池
上面的程式碼可能看起來不是那麼容易理解,下面我們一句一句解釋: 首先,判斷提交的任務command是否為null,若是null,則丟擲空指標異常; 接著是這句,這句要好好理解一下: if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(c
Java多執行緒-執行緒池Executors
概覽 通過上一篇對ThreadPoolExecutor的構造方法分析可以感受到,通過ThreadPoolExecutor來建立執行緒池是比較複雜的,引數比較多,考慮因素也多。 因此java自己提供了一個工廠類Executors,裡面提供了一些方法,用
Java多執行緒三:執行緒池和Executors類解析
執行緒池 多執行緒技術主要解決處理器單元內多個執行緒執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。 假設一個伺服器完成一項任務所需時間為:T1 建立執行緒時間,T2 線上程中執行任務的時間,T3 銷燬執行緒時間。 如果:T1 +
JAVA多執行緒(三) 執行緒池和鎖的深度化
github演示程式碼地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/src/main/java/com/kawa/thread 1.執行緒池 1.1 執行緒池是什麼 Java中的執行緒
java多執行緒7.使用執行緒池
只有當任務都是同類型並且相互獨立時,執行緒池的效能才能達到最佳。如果將執行時間較長的與執行時間較短的任務混合在一起,那麼除非執行緒池很大,否則將可能造成擁塞,如果提交的任務依賴於其他任務,那麼除非執行緒池無線大,否則將可能造成死鎖。 例如飢餓死鎖:執行緒池中的任務需要無限等待一些必須由池中其他任務才能提供的
Java多執行緒 - 執行緒池 ThreadPoolExecutor類的使用
ThreadPoolExecutor類可以非常方便的建立執行緒池物件,而不需要程式設計師設計大量的new去例項化Thread相關的程式碼 最常用的構造方法 (不過threadFactory可以視情況設或不設) ThreadPoolExecutor( &nb
【Java多執行緒】執行緒狀態、執行緒池狀態
執行緒狀態: 執行緒共包括以下5種狀態。1. 新建狀態(New) 執行緒物件被建立後,就進入了新建狀態。例如,Thread thread = new Thread()。2. 就緒狀態(Runnable) 也被稱為“可執行狀態”。執行緒物件被建立後,
Java多執行緒-併發之執行緒池
執行緒池有了解嗎? 答: java.util.concurrent.ThreadPoolExecutor 類就是一個執行緒池。客戶端呼叫ThreadPoolExecutor.submit(Runnable task) 提交任務,執行緒池內部維護的工作者執行緒的數量就是該執行緒池的執行
Java多執行緒(ExecutorService 、Executors、Callable、Future、FutureTask)
前言:我們一般通過繼承Thread類重寫run方法或者實現runnable介面重寫run方法,最後建立和啟動一個執行緒,但是都需要自己建立、啟動Thread物件。執行緒池可以實現幫助我們管理Thread物件,至於要使用幾個執行緒,什麼時候啟動這些執行緒,是開啟多個執行緒還是用單個執行緒來完成
Java多執行緒使用執行緒池實現檔案下載
多執行緒下載原理: 1、基本思路是將檔案分段切割、分段傳輸、分段儲存。 2、分段切割用到HttpUrlConnection物件的setRequestProperty(“Range”, “bytes=” + start + “-” + end)方法。 3、分段傳輸用到HttpU
Java——多執行緒基本使用(四) 執行緒組和執行緒池的使用,工廠設計模式的使用
1.執行緒組的概述和使用 Java中使用ThreadGroup來表示執行緒組,它可以對一批執行緒進行分類管理,Java允許程式直接對執行緒組進行控制。 &n
Java多執行緒-執行緒池ThreadPoolExecutor構造方法和規則 Java多執行緒-執行緒池ThreadPoolExecutor構造方法和規則
Java多執行緒-執行緒池ThreadPoolExecutor構造方法和規則 2017年05月03日 17:15:37 閱讀數:40542 為什麼用執行緒池 部落格地址 http://blog.csdn.ne
《Java多執行緒程式設計實戰》—— 第9章 Thread Pool(執行緒池)模式
一個系統中的執行緒相對於其所要處理的任務而言,是一種非常有限的資源。執行緒不僅在執行任務時需要消耗CPU時間和記憶體等資源,執行緒物件(Thread例項)本身以及執行緒所需的呼叫棧(Call Stack)也佔用記憶體,並且Java中建立一個執行緒往往意味著JVM會建立相應的依賴於宿主機作業系
(CSDN遷移)JAVA多執行緒實現-單執行緒化執行緒池newSingleThreadExecutor
JAVA通過Executors提供了四種執行緒池,單執行緒化執行緒池(newSingleThreadExecutor)、可控最大併發數執行緒池(newFixedThreadPool)、可回收快取執行緒池(newCachedThreadPool)、支援定時與週期性任務的執行緒池(newScheduledThre
(CSDN遷移) JAVA多執行緒實現-可控最大併發數執行緒池(newFixedThreadPool)
上篇文章中介紹了單執行緒化執行緒池newSingleThreadExecutor,可控最大併發數執行緒池(newFixedThreadPool)與其最大的區別是可以通知執行多個執行緒,可以簡單的將newSingleThreadExecutor理解為newFixedThreadPool(1)。例如執行一下兩個程
java多執行緒(13)執行緒池
當程式中需要大量並且生存週期很短的執行緒時候,可以考慮使用執行緒池,執行緒池的工作原理是線上程池創立的時候就建立大量空閒的執行緒,當一個Runnable或者Callable物件傳到執行緒池的時候,執行緒池就啟動一執行緒來執行他們的run或者call方法,當run或者call方
Java多執行緒2.8.執行緒池2
執行緒池 1、實現Callable介面來實現執行緒池 Callable:是帶泛型的介面。 這裡指定的泛型其實是call()方法的返回值型別。 (1)建立實現Callable類的執行緒類 pa
Java多執行緒系列--“JUC執行緒池”01之 執行緒池架構
概要 前面分別介紹了”Java多執行緒基礎”、”JUC原子類”和”JUC鎖”。本章介紹JUC的最後一部分的內容——執行緒池。內容包括: 執行緒池架構圖 執行緒池示例 執行緒池架構圖 執行緒池的架構圖如下: 1、Executor