[TOC]
線程池
1. 并發(fā)隊(duì)列:阻塞隊(duì)列和非阻塞隊(duì)列
區(qū)別如下:
入隊(duì):
- 非阻塞隊(duì)列:當(dāng)隊(duì)列中滿了的時(shí)候,放入數(shù)據(jù)铭腕,數(shù)據(jù)丟失
- 阻塞隊(duì)列:當(dāng)隊(duì)列滿了的時(shí)候,進(jìn)行等待,什么時(shí)候隊(duì)列中有出隊(duì)的數(shù)據(jù)谴餐,那么第 11 個(gè)再放進(jìn)入
出隊(duì):
- 非阻塞隊(duì)列:如果現(xiàn)在隊(duì)列中沒有元素,取數(shù)據(jù)呆抑,得到的是 null
- 阻塞隊(duì)列:等待岂嗓,什么時(shí)候放進(jìn)去,再取出來
線程池是使用阻塞隊(duì)列鹊碍。
2. 線程池原理:ThreadPoolExecutor 底層原理解析
2. 1線程的生命周期
從出生到死亡的階段厌殉。
2.2 線程池工作原理
ThreadPoolExecutor t = new ThreadPoolExecutor(1, 3, 0, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>(3));
參數(shù)含義:
- 1:核心線程數(shù)
- 3:最大線程數(shù)
- 0 和
TimeUnit.MICROSECONDS
:當(dāng)任務(wù)量大于隊(duì)列長(zhǎng)度需要?jiǎng)?chuàng)建線程的時(shí)候食绿,新創(chuàng)建的這個(gè)線程假如把隊(duì)列的任務(wù)都執(zhí)行完了,那么等待新任務(wù)的空閑時(shí)間就是這個(gè) -
new LinkedBlockingDeque<>(3))
:阻塞隊(duì)列:- 方法有參數(shù):隊(duì)列長(zhǎng)度為 3
- 方法無參數(shù):隊(duì)列長(zhǎng)度為
Integer.MAX_VALUE
執(zhí)行流程圖如下所示:
2.3 舉個(gè)例子
package com.test.jdk8;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestThreadPoolExecutor {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3));
// 利用線程池里的線程公罕,開始執(zhí)行任務(wù)
// 執(zhí)行第一個(gè)任務(wù)
pool.execute(new TestThread());
// 執(zhí)行下面三個(gè)任務(wù)器紧,放入阻塞隊(duì)列,阻塞隊(duì)列滿:
pool.execute(new TestThread());
pool.execute(new TestThread());
pool.execute(new TestThread());
// 執(zhí)行第 4個(gè)任務(wù)楼眷,創(chuàng)建新線程铲汪,分?jǐn)側(cè)蝿?wù)
pool.execute(new TestThread());
// 執(zhí)行第 5 個(gè)任務(wù),創(chuàng)建新創(chuàng)建罐柳,線程數(shù)大于最大線程數(shù)掌腰,報(bào)錯(cuò)
pool.execute(new TestThread());
// 關(guān)閉線程池
pool.shutdown();
}
}
class TestThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
3. 線程池的分類
1. newCachedThreadPool 可緩存線程池
創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過處理需要张吉,可靈活回收空閑線程齿梁,若無可回收,則新建線程芦拿。示例代碼如下:
package ThreadTest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
// lambda 表達(dá)式, 實(shí)現(xiàn) new Runnable() 的 run() 方法
es.execute(() -> System.out.println(Thread.currentThread().getName()));
}
es.shutdown();
}
}
查看 newCachedThreadPool
源碼士飒,可知:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
該線程池的核心線程數(shù)為 0, 最大線程數(shù)為 Integer.MAX_VALUE
蔗崎,將會(huì)根據(jù)需要?jiǎng)?chuàng)建新線程酵幕,新線程的數(shù)量不大于 Integer.MAX_VALUE
,線程執(zhí)行任務(wù)結(jié)束后被釋放可重復(fù)使用該線程執(zhí)行另一個(gè)任務(wù)缓苛。
部分執(zhí)行結(jié)果如下:
pool-1-thread-6
pool-1-thread-11
pool-1-thread-6
pool-1-thread-10
pool-1-thread-4
pool-1-thread-11
pool-1-thread-2
2. newFixedThreadPool 定長(zhǎng)線程池
創(chuàng)建一個(gè)定長(zhǎng)線程池芳撒,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待未桥。示例代碼如下:
package ThreadTest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(3);
for (int i = 0; i < 100; i++) {
// lambda 表達(dá)式, 實(shí)現(xiàn) new Runnable() 的 run() 方法
es.execute(() -> System.out.println(Thread.currentThread().getName()));
}
es.shutdown();
}
}
查看 newFixedThreadPool
源碼笔刹,可知:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
傳入的參數(shù)即為核心線程數(shù)和最大線程數(shù),核心線程數(shù)和最大線程數(shù)的數(shù)量是相等的冬耿。
所以上述示例代碼的執(zhí)行結(jié)果的線程數(shù)就為 3舌菜,部分執(zhí)行結(jié)果如下:
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-3
pool-1-thread-1
3. newScheduledThreadPool 定時(shí)線程池
創(chuàng)建一個(gè)定時(shí)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行亦镶。延遲執(zhí)行示例代碼如下:
package ThreadTest;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
for (int i = 0; i < 100; i++) {
ses.schedule(() -> System.out.println(Thread.currentThread().getName()), 3, TimeUnit.SECONDS);
}
ses.shutdown();
}
}
查看 newScheduledThreadPool
源碼日月,如下:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
可知,newScheduledThreadPool
傳入的參數(shù)即為核心線程數(shù)缤骨,最大線程數(shù)為 Integer.MAX_VALUE
爱咬。
上述代碼通過設(shè)置延遲參數(shù) 3, 單位 TimeUnit.SECONDS
绊起,延遲三秒后執(zhí)行任務(wù)精拟,創(chuàng)建的線程數(shù)為 2。執(zhí)行部分結(jié)果如下:
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
4. newSingleThreadExecutor 單例線程池
創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù)蜂绎,保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行栅表。示例代碼如下:
package ThreadTest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
ExecutorService es = Executors.newSingleThreadExecutor();
for (int i = 0; i < 100; i++) {
es.execute(() -> System.out.println(Thread.currentThread().getName()));
}
es.shutdown();
}
}
查看 newSingleThreadExecutor
源碼,可知:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
核心線程數(shù)和最大線程數(shù)都為 1师枣,執(zhí)行完任務(wù)后線程的存活時(shí)間為 0谨读,即創(chuàng)建出來的線程只會(huì)執(zhí)行一次任務(wù),保證單例執(zhí)行坛吁。
運(yùn)行部分結(jié)果如下:
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1