概念
線程的創建與銷燬都需要銷燬資源,爲了避免頻繁的創建與銷燬線程,可以讓創建的線程進行復用。類似數據庫連接池的概念,
Java中的線程池
Java通過Executors提供四種線程池,分別爲:
newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。
newFixedThreadPool 創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
newScheduledThreadPool 創建一個定長線程池,支持定時及週期性任務執行。
newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
緩存線程池(CachedThreadPool )
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId() + " : " + index);
}
});
}
cachedThreadPool.shutdown();
}
}
打印結果發現 執行上一個線程處理的過來打印,所以都是同一個線程完成任務.
9 : 0
9 : 1
9 : 2
9 : 3
9 : 4
9 : 5
9 : 6
9 : 7
9 : 8
9 : 9
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId() + " : " + index);
}
});
}
cachedThreadPool.shutdown();
}
}
打印結果,發現當前線程池的線程處理不過來,自動創建新的線程來做處理
9 : 0
12 : 3
10 : 1
11 : 2
14 : 5
15 : 6
13 : 4
16 : 7
14 : 8
16 : 9
定長線程池(FixedThreadPool)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(Thread.currentThread().getId() + " : " + index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
fixedThreadPool.shutdown();
}
}
打印結果 始終只有三個線程處理,沒有來得及處理的排隊等待
9 : 0
10 : 1
11 : 2
10 : 3
11 : 5
9 : 4
11 : 6
9 : 8
10 : 7
10 : 9
調度計劃線程池(ScheduledThreadPool)
三秒鐘之後開始執行,執行完畢就關閉,不循環
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
//三秒後執行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
scheduledThreadPool.shutdown();
}
}
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId() + " : delay 3 seconds, and excute every 2 seconds");
}
}, 3, 2, TimeUnit.SECONDS);
}
}
打印結果: 三秒後開始執行打印,之後沒兩秒執行一次,不斷輪詢,每次執行的線程不固定
9 : delay 3 seconds, and excute every 2 seconds
9 : delay 3 seconds, and excute every 2 seconds
11 : delay 3 seconds, and excute every 2 seconds
9 : delay 3 seconds, and excute every 2 seconds
12 : delay 3 seconds, and excute every 2 seconds
11 : delay 3 seconds, and excute every 2 seconds
13 : delay 3 seconds, and excute every 2 seconds
9 : delay 3 seconds, and excute every 2 seconds
單線程線程池(SingleThreadExecutor)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 20; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(Thread.currentThread().getId() + " : " + index);
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
打印結果: 發現每次都是同一個線程執行
9 : 0
9 : 1
9 : 2
9 : 3
9 : 4
9 : 5
9 : 6
9 : 7
9 : 8
9 : 9
9 : 10
9 : 11
9 : 12
9 : 13
9 : 14
9 : 15
9 : 16
9 : 17
9 : 18
9 : 19
自定義線程池(ThreadPoolExecutor)
說明
上面四種線程池除了(ScheduledThreadPool)外都繼承與ThreadPoolExecutor類,只不過傳遞的參數不同而已.
ThreadPoolExecutor的構造函數如下
corePoolSize:指定線程池中線程數量
maximumPoolSize : 指定線程池中最大線程數
keepAliveTime : 當線程池線程數量超過corePoolSize時,多餘的空閒線程存活時間.
unit : keepAliveTime 參數的單位
workQueue : 任務隊列,被加入進來執行的任務,但是未被執行的任務隊列
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
自定義線程池
上面既然發現jdk提供的線程池來自於ThreadPoolExecutor,
那麼一樣可以自定義
ExecutorService singleThreadExecutor = new ThreadPoolExecutor(10, 10, 0, TimeUnit.DAYS,
new LinkedBlockingQueue<Runnable>(),new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
return t;
}
});
擴展線程池
執行之前,結束之後,終止調用的方法.
ExecutorService es = new ThreadPoolExecutor(10, 10, 0, TimeUnit.DAYS, new LinkedBlockingQueue<Runnable>()){
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
}
@Override
protected void terminated() {
super.terminated();
}
};