什么叫線程
線程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位谣光。它被包含在進(jìn)程之中檩淋,是進(jìn)程中的實(shí)際運(yùn)作單位。
進(jìn)程(Process)是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)萄金,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位蟀悦,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)(百度百科)
創(chuàng)建線程的三種方式
一、繼承Thread類(lèi):
class MyThread extends Thread {
public void run() {
//這里是線程要執(zhí)行的任務(wù)
}
}
Thread t = new MyThread();
t.start();
二氧敢、實(shí)現(xiàn)Runnable接口
class MyRunnable implements Runnable {
...
public void run() {
//這里是新線程需要執(zhí)行的任務(wù)
}
}
Runnable r = new MyRunnable();
Thread t = new Thread(r);
三日戈、通過(guò)Callable和Future創(chuàng)建線程:
1、Callable與Runnable對(duì)比
public interface Runnable {
public abstract void run();
}
由于run()方法返回值為void類(lèi)型孙乖,所以在執(zhí)行完任務(wù)之后無(wú)法返回任何結(jié)果浙炼。
Callable位于java.util.concurrent包下份氧,它也是一個(gè)接口,在它里面也只聲明了一個(gè)方法弯屈,只不過(guò)這個(gè)方法叫做call():
public interface Callable<V> {
V call() throws Exception;
}
這是一個(gè)泛型接口蜗帜,call()函數(shù)返回的類(lèi)型就是傳遞進(jìn)來(lái)的V類(lèi)型。
2资厉、Future
Future就是對(duì)于具體的Runnable或者Callable任務(wù)的執(zhí)行結(jié)果進(jìn)行取消厅缺、查詢是否完成、獲取結(jié)果酌住。必要時(shí)可以通過(guò)get方法獲取執(zhí)行結(jié)果店归,該方法會(huì)阻塞直到任務(wù)返回結(jié)果阎抒。
Future類(lèi)位于java.util.concurrent包下酪我,它是一個(gè)接口:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
在Future接口中聲明了5個(gè)方法,下面依次解釋每個(gè)方法的作用:
cancel 方法 用來(lái)取消任務(wù)且叁,如果取消任務(wù)成功則返回true都哭,如果取消任務(wù)失敗則返回false。參數(shù)mayInterruptIfRunning表示是否允許取消正在執(zhí)行卻沒(méi)有執(zhí)行完畢的任務(wù)逞带,如果設(shè)置true欺矫,則表示可以取消正在執(zhí)行過(guò)程中的任務(wù)。如果任務(wù)已經(jīng)完成展氓,則無(wú)論mayInterruptIfRunning為true還是false穆趴,此方法肯定返回false,即如果取消已經(jīng)完成的任務(wù)會(huì)返回false遇汞;如果任務(wù)正在執(zhí)行未妹,若mayInterruptIfRunning設(shè)置為true,則返回true空入,若mayInterruptIfRunning設(shè)置為false络它,則返回false;如果任務(wù)還沒(méi)有執(zhí)行歪赢,則無(wú)論mayInterruptIfRunning為true還是false化戳,肯定返回true。
isCancelled 方法表示任務(wù)是否被取消成功埋凯,如果在任務(wù)正常完成前被取消成功点楼,則返回 true。
isDone 方法表示任務(wù)是否已經(jīng)完成白对,若任務(wù)完成盟步,則返回true;
get() 方法用來(lái)獲取執(zhí)行結(jié)果躏结,這個(gè)方法會(huì)產(chǎn)生阻塞却盘,會(huì)一直等到任務(wù)執(zhí)行完畢才返回狰域;
get(long timeout, TimeUnit unit)用來(lái)獲取執(zhí)行結(jié)果,如果在指定時(shí)間內(nèi)黄橘,還沒(méi)獲取到結(jié)果兆览,就直接返回null。
也就是說(shuō)Future提供了三種功能:
1)判斷任務(wù)是否完成塞关;
2)能夠中斷任務(wù)抬探;
3)能夠獲取任務(wù)執(zhí)行結(jié)果。
因?yàn)镕uture只是一個(gè)接口帆赢,所以是無(wú)法直接用來(lái)創(chuàng)建對(duì)象使用的小压,因此就有了下面的FutureTask。
3椰于、FutureTask
public class FutureTask<V> implements RunnableFuture<V>
FutureTask類(lèi)實(shí)現(xiàn)了RunnableFuture接口怠益,我們看一下RunnableFuture接口的實(shí)現(xiàn):
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
可以看出RunnableFuture繼承了Runnable接口和Future接口,而FutureTask實(shí)現(xiàn)了RunnableFuture接口瘾婿。所以它既可以作為Runnable被線程執(zhí)行蜻牢,又可以作為Future得到Callable的返回值。
FutureTask提供了2個(gè)構(gòu)造器:
public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}
事實(shí)上偏陪,F(xiàn)utureTask是Future接口的一個(gè)唯一實(shí)現(xiàn)類(lèi)抢呆。
具體使用
public class MyCallable implements Callable<String>{
@Override
public String call() throws Exception {
return "hello";
}
}
FutureTask futureTask = new FutureTask(new MyCallable());
futureTask.run();
try {
String str = (String) futureTask.get();
Log.e("myMessage"," "+str);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
或
1.使用Callable+Future獲取執(zhí)行結(jié)果
public class Test {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
Future<Integer> result = executor.submit(task);
executor.shutdown();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("主線程在執(zhí)行任務(wù)");
try {
System.out.println("task運(yùn)行結(jié)果"+result.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("所有任務(wù)執(zhí)行完畢");
}
}
class Task implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("子線程在進(jìn)行計(jì)算");
Thread.sleep(3000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
}
2.使用Callable+FutureTask獲取執(zhí)行結(jié)果
public class Test {
public static void main(String[] args) {
//第一種方式
ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
executor.submit(futureTask);
executor.shutdown();
//第二種方式,注意這種方式和第一種方式效果是類(lèi)似的笛谦,只不過(guò)一個(gè)使用的是ExecutorService抱虐,一個(gè)使用的是Thread
/*Task task = new Task();
FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
Thread thread = new Thread(futureTask);
thread.start();*/
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("主線程在執(zhí)行任務(wù)");
try {
System.out.println("task運(yùn)行結(jié)果"+futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("所有任務(wù)執(zhí)行完畢");
}
}
class Task implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("子線程在進(jìn)行計(jì)算");
Thread.sleep(3000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
}
線程的生命周期
線程共包括以下 5 種狀態(tài):
- 新建狀態(tài)(New): 線程對(duì)象被創(chuàng)建后,就進(jìn)入了新建狀態(tài)饥脑。例如恳邀,Thread thread = new Thread()。
- 就緒狀態(tài)(Runnable): 也被稱為“可執(zhí)行狀態(tài)”好啰。線程對(duì)象被創(chuàng)建后轩娶,其它線程調(diào)用了該對(duì)象的start()方法,從而來(lái)啟動(dòng)該線程框往。例如鳄抒,thread.start()。處于就緒狀態(tài)的線程椰弊,隨時(shí)可能被CPU調(diào)度執(zhí)行许溅。
- 運(yùn)行狀態(tài)(Running): 線程獲取CPU權(quán)限進(jìn)行執(zhí)行。需要注意的是秉版,線程只能從就緒狀態(tài)進(jìn)入到運(yùn)行狀態(tài)贤重。
- 阻塞狀態(tài)(Blocked): 阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行清焕。直到線程進(jìn)入就緒狀態(tài)并蝗,才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)祭犯。阻塞的情況分三種:
(01) 等待阻塞 -- 通過(guò)調(diào)用線程的wait()方法,讓線程等待某工作的完成滚停。
(02) 同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因?yàn)殒i被其它線程所占用)沃粗,它會(huì)進(jìn)入同步阻塞狀態(tài)。
(03) 其他阻塞 -- 通過(guò)調(diào)用線程的sleep()或join()或發(fā)出了I/O請(qǐng)求時(shí)键畴,線程會(huì)進(jìn)入到阻塞狀態(tài)最盅。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)起惕、或者I/O處理完畢時(shí)涡贱,線程重新轉(zhuǎn)入就緒狀態(tài)。 - 死亡狀態(tài)(Dead): 線程執(zhí)行完了或者因異常退出了run()方法惹想,該線程結(jié)束生命周期问词。
Thread類(lèi)的常用方法除了我們之前提到的用于啟動(dòng)線程的start外還有:
(1)sleep方法
sleep 方法,這是一個(gè)靜態(tài)方法勺馆,作用是讓當(dāng)前線程進(jìn)入休眠狀態(tài)(但線程不會(huì)釋放已獲取的鎖)戏售,這個(gè)休眠狀態(tài)其實(shí)就是我們上面提到過(guò)的Time Waiting狀態(tài)侨核,從休眠狀態(tài)“蘇醒”后草穆,線程會(huì)進(jìn)入到Runnable狀態(tài)。sleep方法有兩個(gè)重載版本搓译,聲明分別如下:
public static native void sleep(long millis) throws InterruptedException; //讓當(dāng)前線程休眠millis指定的毫秒數(shù)
public static native void sleep(long millis, int nanos) throws InterruptedException; //在毫秒數(shù)的基礎(chǔ)上還指定了納秒數(shù)悲柱,控制粒度更加精細(xì)
(2)join 方法
join 方法,這是一個(gè)實(shí)例方法些己,在當(dāng)前線程中對(duì)一個(gè)線程對(duì)象調(diào)用join方法會(huì)導(dǎo)致當(dāng)前線程停止運(yùn)行豌鸡,等那個(gè)線程運(yùn)行完畢后再接著運(yùn)行當(dāng)前線程。也就是說(shuō)段标,把當(dāng)前線程還沒(méi)執(zhí)行的部分“接到”另一個(gè)線程后面去涯冠,另一個(gè)線程運(yùn)行完畢后,當(dāng)前線程再接著運(yùn)行逼庞。join方法有以下重載版本:
public final synchronized void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException;
public final synchronized void join(long millis, int nanos) throws InterruptedException;
無(wú)參數(shù)的join表示當(dāng)前線程一直等到另一個(gè)線程運(yùn)行完畢蛇更,這種情況下當(dāng)前線程會(huì)處于Wating狀態(tài);帶參數(shù)的表示當(dāng)前線程只等待指定的時(shí)間赛糟,這種情況下當(dāng)前線程會(huì)處于Time Waiting狀態(tài)派任。當(dāng)前線程通過(guò)調(diào)用join方法進(jìn)入Time Waiting或Waiting狀態(tài)后,會(huì)釋放已經(jīng)獲取的鎖璧南。實(shí)際上掌逛,join方法內(nèi)部調(diào)用了Object類(lèi)的實(shí)例方法wait,關(guān)于這個(gè)方法我們下面會(huì)具體介紹司倚。
(3)yield 方法
yield 方法豆混,這是一個(gè)靜態(tài)方法篓像,作用是讓當(dāng)前線程“讓步”,目的是為了讓優(yōu)先級(jí)不低于當(dāng)前線程的線程有機(jī)會(huì)運(yùn)行皿伺,這個(gè)方法不會(huì)釋放鎖遗淳。
(4)interrupt 方法
interrupt 方法,這是一個(gè)實(shí)例方法心傀。每個(gè)線程都有一個(gè)中斷狀態(tài)標(biāo)識(shí)屈暗,這個(gè)方法的作用就是將相應(yīng)線程的中斷狀態(tài)標(biāo)記為true,這樣相應(yīng)的線程調(diào)用isInterrupted方法就會(huì)返回true脂男。通過(guò)使用這個(gè)方法养叛,能夠終止那些通過(guò)調(diào)用可中斷方法進(jìn)入阻塞狀態(tài)的線程。常見(jiàn)的可中斷方法有sleep宰翅、wait弃甥、join,這些方法的內(nèi)部實(shí)現(xiàn)會(huì)時(shí)不時(shí)的檢查當(dāng)前線程的中斷狀態(tài)汁讼,若為true會(huì)立刻拋出一個(gè)InterruptedException異常淆攻,從而終止當(dāng)前線程。
(5)wait方法
wait方法是Object類(lèi)中定義的實(shí)例方法嘿架。在指定對(duì)象上調(diào)用wait方法能夠讓當(dāng)前線程進(jìn)入阻塞狀態(tài)(前提是當(dāng)前線程持有該對(duì)象的內(nèi)部鎖(monitor))瓶珊,此時(shí)當(dāng)前線程會(huì)釋放已經(jīng)獲取的那個(gè)對(duì)象的內(nèi)部鎖,這樣一來(lái)其他線程就可以獲取這個(gè)對(duì)象的內(nèi)部鎖了耸彪。當(dāng)其他線程獲取了這個(gè)對(duì)象的內(nèi)部鎖伞芹,進(jìn)行了一些操作后可以調(diào)用notify方法來(lái)喚醒正在等待該對(duì)象的線程。
(6)notify/notifyAll方法
notify/notifyAll方法也是Object類(lèi)中定義的實(shí)例方法蝉娜。它倆的作用是喚醒正在等待相應(yīng)對(duì)象的線程唱较,區(qū)別在于前者喚醒一個(gè)等待該對(duì)象的線程,而后者喚醒所有等待該對(duì)象的線程召川。這么說(shuō)比較抽象南缓,下面我們來(lái)舉一個(gè)具體的例子來(lái)說(shuō)明以下wait和notify/notifyAll的用法。請(qǐng)看以下代碼
public class Test {
private int queueSize = 10;
private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
public static void main(String[] args) {
Test test = new Test();
Producer producer = test.new Producer();
Consumer consumer = test.new Consumer();
producer.start();
consumer.start();
}
class Consumer extends Thread{
@Override
public void run() {
consume();
}
private void consume() {
while(true){
synchronized (queue) {
while(queue.size() == 0){
try {
System.out.println("隊(duì)列空荧呐,等待數(shù)據(jù)");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify();
}
}
queue.poll(); //每次移走隊(duì)首元素
queue.notify();
System.out.println("從隊(duì)列取走一個(gè)元素汉形,隊(duì)列剩余"+queue.size()+"個(gè)元素");
}
}
}
}
class Producer extends Thread{
@Override
public void run() {
produce();
}
private void produce() {
while(true){
synchronized (queue) {
while(queue.size() == queueSize){
try {
System.out.println("隊(duì)列滿,等待有空余空間");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify();
}
}
queue.offer(1); //每次插入一個(gè)元素
queue.notify();
System.out.println("向隊(duì)列取中插入一個(gè)元素坛增,隊(duì)列剩余空間:"+(queueSize-queue.size()));
}
}
}
}
}
以上代碼描述的是經(jīng)典的“生產(chǎn)者-消費(fèi)者”問(wèn)題获雕。Consumer類(lèi)代表消費(fèi)者,Producer類(lèi)代表生產(chǎn)者收捣。在生產(chǎn)者進(jìn)行生產(chǎn)之前届案,會(huì)獲取queue的內(nèi)部鎖(monitor)。然后判斷隊(duì)列是否已滿罢艾,若滿了則無(wú)法再生產(chǎn)楣颠,所以調(diào)用queue.wait方法尽纽,從而等待在queue對(duì)象上。(釋放了queue的內(nèi)部鎖)此時(shí)消費(fèi)者能夠能夠獲取queue的monitor從而進(jìn)入consume方法童漩,這樣一來(lái)它就會(huì)通過(guò)queue.poll方法進(jìn)行消費(fèi)弄贿,于是隊(duì)列不再滿了,接著它調(diào)用queue.notify方法來(lái)通知正在等待的生產(chǎn)者矫膨,生產(chǎn)者就會(huì)從剛才阻塞的wait方法中返回差凹。同理,當(dāng)隊(duì)列空時(shí)侧馅,消費(fèi)者也會(huì)等待 生產(chǎn)者來(lái)喚醒危尿。
線程池
一.Java中的ThreadPoolExecutor類(lèi)
java.uitl.concurrent.ThreadPoolExecutor類(lèi)是線程池中最核心的一個(gè)類(lèi),因此如果要透徹地了解Java中的線程池馁痴,必須先了解這個(gè)類(lèi)谊娇。下面我們來(lái)看一下ThreadPoolExecutor類(lèi)的具體實(shí)現(xiàn)源碼。
在ThreadPoolExecutor類(lèi)中提供了四個(gè)構(gòu)造方法:
public class ThreadPoolExecutor extends AbstractExecutorService {
.....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
...
}
從上面的代碼可以得知罗晕,ThreadPoolExecutor繼承了AbstractExecutorService類(lèi)济欢,并提供了四個(gè)構(gòu)造器,事實(shí)上小渊,通過(guò)觀察每個(gè)構(gòu)造器的源碼具體實(shí)現(xiàn)法褥,發(fā)現(xiàn)前面三個(gè)構(gòu)造器都是調(diào)用的第四個(gè)構(gòu)造器進(jìn)行的初始化工作。
下面解釋下一下構(gòu)造器中各個(gè)參數(shù)的含義:
corePoolSize:核心池的大小粤铭,這個(gè)參數(shù)跟后面講述的線程池的實(shí)現(xiàn)原理有非常大的關(guān)系挖胃。在創(chuàng)建了線程池后杂靶,默認(rèn)情況下梆惯,線程池中并沒(méi)有任何線程,而是等待有任務(wù)到來(lái)才創(chuàng)建線程去執(zhí)行任務(wù)吗垮,除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法垛吗,從這2個(gè)方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思烁登,即在沒(méi)有任務(wù)到來(lái)之前就創(chuàng)建corePoolSize個(gè)線程或者一個(gè)線程怯屉。默認(rèn)情況下,在創(chuàng)建了線程池后饵沧,線程池中的線程數(shù)為0锨络,當(dāng)有任務(wù)來(lái)之后,就會(huì)創(chuàng)建一個(gè)線程去執(zhí)行任務(wù)狼牺,當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后羡儿,就會(huì)把到達(dá)的任務(wù)放到緩存隊(duì)列當(dāng)中;
maximumPoolSize:線程池最大線程數(shù)是钥,這個(gè)參數(shù)也是一個(gè)非常重要的參數(shù)掠归,它表示在線程池中最多能創(chuàng)建多少個(gè)線程缅叠;
keepAliveTime:表示線程沒(méi)有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會(huì)終止。默認(rèn)情況下虏冻,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí)肤粱,keepAliveTime才會(huì)起作用,直到線程池中的線程數(shù)不大于corePoolSize厨相,即當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí)领曼,如果一個(gè)線程空閑的時(shí)間達(dá)到keepAliveTime,則會(huì)終止蛮穿,直到線程池中的線程數(shù)不超過(guò)corePoolSize悯森。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時(shí)绪撵,keepAliveTime參數(shù)也會(huì)起作用瓢姻,直到線程池中的線程數(shù)為0;
unit:參數(shù)keepAliveTime的時(shí)間單位音诈,有7種取值幻碱,在TimeUnit類(lèi)中有7種靜態(tài)屬性:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小時(shí)
TimeUnit.MINUTES; //分鐘
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //納秒
workQueue:一個(gè)阻塞隊(duì)列,用來(lái)存儲(chǔ)等待執(zhí)行的任務(wù)细溅,這個(gè)參數(shù)的選擇也很重要褥傍,會(huì)對(duì)線程池的運(yùn)行過(guò)程產(chǎn)生重大影響,一般來(lái)說(shuō)喇聊,這里的阻塞隊(duì)列有以下幾種選擇:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
ArrayBlockingQueue和PriorityBlockingQueue使用較少恍风,一般使用LinkedBlockingQueue和Synchronous。線程池的排隊(duì)策略與BlockingQueue有關(guān)誓篱。
threadFactory:線程工廠朋贬,主要用來(lái)創(chuàng)建線程;
handler:表示當(dāng)拒絕處理任務(wù)時(shí)的策略窜骄,有以下四種取值:
ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常锦募。
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常邻遏。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù)糠亩,然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過(guò)程)
ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
常用的線程池
FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
如上,F(xiàn)ixedThreadPool中核心線程數(shù)等于線程池可容納的最大線程數(shù)准验,這意味著FixedThreadPool中只存在核心線程赎线,并且核心線程處于空閑狀態(tài)也不會(huì)被終止。這表示FixedThreadPool線程池能快速地響應(yīng)外界的任務(wù)請(qǐng)求糊饱。
當(dāng)所有核心線程都處于活動(dòng)狀態(tài)時(shí)垂寥,后續(xù)提交的任務(wù)就會(huì)進(jìn)入LinkedBlockingQueue隊(duì)列中,此隊(duì)列默認(rèn)的容量是Integer.MAX_VALUE,即可理解為無(wú)限制矫废。
CacheThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
如上盏缤,CacheThreadPool線程池不存在核心線程,但是它可容納的非核心線程數(shù)可看作是無(wú)限制的蓖扑,又因?yàn)镾ynchronousQueue隊(duì)列通常是無(wú)法存儲(chǔ)元素的唉铜,這就表示,當(dāng)提交了一個(gè)線程任務(wù)時(shí)律杠,因?yàn)闆](méi)有核心線程存在潭流,并且也無(wú)法插入到SynchronousQueue隊(duì)列中排隊(duì)等外,所以就會(huì)使用一個(gè)非核心線程來(lái)執(zhí)行這個(gè)任務(wù)柜去。因?yàn)樵O(shè)置了60s的空閑時(shí)長(zhǎng)灰嫉,所以被用來(lái)執(zhí)行任務(wù)的非核心線程會(huì)先考慮處于空閑狀態(tài)的非核心線程,如果沒(méi)有空閑的線程嗓奢,就會(huì)創(chuàng)建新線程來(lái)執(zhí)行任務(wù)讼撒。當(dāng)任務(wù)都執(zhí)行完成后,并且超過(guò)了空閑時(shí)長(zhǎng)股耽,那么線程就會(huì)被回收根盒,當(dāng)沒(méi)有提交任務(wù),并且所有空閑線程都被回收后物蝙,CacheThreadPool是不會(huì)占用系統(tǒng)資源的炎滞。從CacheThreadPool的特性來(lái)看,可以用它來(lái)執(zhí)行大量的耗時(shí)較少的任務(wù)诬乞。
SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
如上册赛,SingleThreadExecutor線程池中只存在一個(gè)核心線程,并且任務(wù)隊(duì)LinkedBlockingQueue的容量是無(wú)限制的震嫉。這意味著使用該線程池執(zhí)行線程任務(wù)森瘪,同一時(shí)間只有一個(gè)線程任務(wù)在執(zhí)行,在執(zhí)行中的任務(wù)沒(méi)有完成之前责掏,后續(xù)到來(lái)的線程任務(wù)都會(huì)進(jìn)入LinkedBlockingQueue隊(duì)列中排隊(duì)等待柜砾。SingleThreadExecutor線程池使用同一個(gè)線程按任務(wù)提交順序執(zhí)行多個(gè)線程任務(wù),使得這些任務(wù)之間不需要處理線程同步的問(wèn)題换衬。
ScheduledThreadPool
//Executors.java
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
ScheduledThreadPoolExecutor.java
private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
ScheduledThreadPool線程池主要用于執(zhí)行延時(shí)任務(wù),或重復(fù)執(zhí)行某個(gè)任務(wù)证芭。線程任務(wù)通過(guò)
ScheduledExecutorService類(lèi)的 schedule|scheduleAtFixedRate|scheduleWithFixedDelay
方法提交到線程池中瞳浦。