這篇文章給大家介紹線程池的實現(xiàn)原理是什么,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
創(chuàng)新互聯(lián)IDC提供業(yè)務:成都托管服務器,成都服務器租用,成都托管服務器,重慶服務器租用等四川省內(nèi)主機托管與主機租用業(yè)務;數(shù)據(jù)中心含:雙線機房,BGP機房,電信機房,移動機房,聯(lián)通機房。
線程是不是越多好?
線程在Java中是一個對象, 更是操作系統(tǒng)的資源, 線程額創(chuàng)建和銷毀都需要時間,如果 創(chuàng)建時間+銷毀時間>執(zhí)行任務時間 就很不合算
Java對象占用堆內(nèi)存,操作系統(tǒng)線程占用系統(tǒng)內(nèi)存, 根據(jù)JVM規(guī)范,一個線程默認最大棧大小為1M, 這個??臻g是要從操作系統(tǒng)內(nèi)存中分配的,線程過多會消耗很多的內(nèi)存
操作系統(tǒng)頻繁切換線程上下文會影響性能
線程池的推出就是為了控制線程數(shù)量
線程池管理器:
用于創(chuàng)建并管理線程池, 包括創(chuàng)建線程池, 銷毀線程池, 添加新任務
工作線程:
線程池中的線程, 在沒有任務時處于等待狀態(tài), 可以循環(huán)的執(zhí)行任務
任務接口:
每個任務必須實現(xiàn)的接口,以供工作線程任務調(diào)度的執(zhí)行, 它主要規(guī)定了任務的入口,任務執(zhí)行完后的收尾工作,任務的執(zhí)行狀態(tài)等
任務隊列:
用于存放沒有處理的任務,提供一種緩沖
ExecutorService
cheduledExecutorService
可以自己實例化線程池, 也可以用Executors創(chuàng)建線程池,方法如下:
newFixedThreadPool(int nThreads): 創(chuàng)建一個固定大小,任務隊列無界的的線程池,核心線程數(shù)=最大線程數(shù)
newCachedThreadPool(): 創(chuàng)建一個大小無界的緩沖線程池,它的任務隊列是一個同步隊列,任務加入加入到池中,如果池中有空閑線程, 則用空閑線程執(zhí)行,如無則創(chuàng)建新線程執(zhí)行,池中的空閑線程超過60秒, 將被銷毀釋放, 線程數(shù)隨任務的多少變化,適用于耗時較小的異步任務, 池的核心線程數(shù)=0, 最大線程數(shù)=Integer.MAX_VALUE
newSingleThreadExecutor(): 只有一個線程來執(zhí)行無界任務隊列的單一線程池,該線程池確保任務按加入的順序一個一個的依次執(zhí)行,當唯一的線程因任務異常中止時,將創(chuàng)建一個新的線程來繼續(xù)執(zhí)行后續(xù)的任務, 與newFixedThreadPool(1)的區(qū)別在于,單一線程池的池大小在newSingleThreadExecutor方法中硬編碼,不能再改變
newScheduledThreadPool(int corePoolSize): 能定時執(zhí)行任務的線程池,該池的核心線程數(shù)由參數(shù)指定,最大線程數(shù)=Integer.MAX_VALUE
是否達到核心線程數(shù)量?
沒達到,創(chuàng)建一個工作線程來執(zhí)行任務
工作隊列是否已滿?
沒滿,則將新提交的任務存儲在任務隊列中
是否達到線程池最大數(shù)量?
則創(chuàng)建一個新的線程來執(zhí)行任務
最后,執(zhí)行拒絕策略來處理這個任務
代碼示例:
package com.neteasy.demo;
import java.util.List;
import java.util.concurrent.*;
/** 線程池的使用 */
public class Demo7 {
/**
* 測試:提交15個執(zhí)行時間需要3秒的任務,看線程池的狀況
*
* @param threadPoolExecutor
* @throws Exception
*/
private void testCommon(ThreadPoolExecutor threadPoolExecutor) throws Exception {
// 測試:提交15個執(zhí)行時間需要3秒的任務,看超過大小的2個,對應的處理情況
for (int i = 0; i < 15; i++) {
int n = i;
threadPoolExecutor.submit(
new Runnable() {
@Override
public void run() {
try {
System.out.println("開始執(zhí)行:" + n);
Thread.sleep(3000L);
System.out.println("執(zhí)行結(jié)束:" + n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println("任務提交成功:" + i);
}
// 查看線程數(shù)量,查看隊列等待數(shù)量
Thread.sleep(500L);
System.out.println("當前線程池線程數(shù)量為:" + threadPoolExecutor.getPoolSize());
System.out.println("當前線程池等待的數(shù)量為" + threadPoolExecutor.getQueue().size());
// 等待15秒,查看線程數(shù)量和隊列數(shù)量(理論上,會被超出核心線程數(shù)量的線程自動銷毀)
Thread.sleep(15000L);
System.out.println("當前線程池線程數(shù)量為:" + threadPoolExecutor.getPoolSize());
System.out.println("當前線程池等待的數(shù)量為:" + threadPoolExecutor.getQueue().size());
}
/**
* 1、線程池信息:核心線程數(shù)量5,最大數(shù)量10,無界隊列,超出核心線程數(shù)量的線程存活時間:5秒, 指定拒絕策略的
*
* @throws Exception
*/
private void threadPoolExecutorTest1() throws Exception {
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS, new LinkedBlockingDeque());
testCommon(threadPoolExecutor);
// 預計結(jié)果:線程池線程數(shù)量為:5,超出數(shù)量的任務,其他的進入隊列中等待被執(zhí)行
}
/**
* 2、 線程池信息:核心線程數(shù)量5,最大數(shù)量10,隊列大小3,超出核心線程數(shù)量的線程存活時間:5秒, 指定拒絕策略的
*
* @throws Exception
*/
private void threadPoolExecutorTest2() throws Exception {
// 創(chuàng)建一個 核心線程數(shù)量為5,最大數(shù)量為10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(
5,
10,
5,
TimeUnit.SECONDS,
new LinkedBlockingDeque(3),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("有任務被拒絕執(zhí)行了");
}
});
testCommon(threadPoolExecutor);
// 預計結(jié)果:
// 1、 5個任務直接分配線程開始執(zhí)行
// 2、 3個任務進入等待隊列
// 3、 隊列不夠用,臨時加開5個線程來執(zhí)行任務(5秒沒活干就銷毀)
// 4、 隊列和線程池都滿了,剩下2個任務,沒資源了,被拒絕執(zhí)行。
// 5、 任務執(zhí)行,5秒后,如果無任務可執(zhí)行,銷毀臨時創(chuàng)建的5個線程
}
/**
* 3、 線程池信息:核心線程數(shù)量5,最大數(shù)量5,無界隊列,超出核心線程數(shù)量的線程存活時間:5秒
*
* @throws Exception
*/
private void threadPoolExecutorTest3() throws Exception {
// 和Executors.newFixedThreadPool(int nThreads)一樣的
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(
5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
testCommon(threadPoolExecutor);
// 預計結(jié):線程池線程數(shù)量為:5,超出數(shù)量的任務,其他的進入隊列中等待被執(zhí)行
}
/**
* 4、 線程池信息:核心線程數(shù)量0,最大數(shù)量Integer.MAX_VALUE,SynchronousQueue隊列,超出核心線程數(shù)量的線程存活時間:60秒
*
* @throws Exception
*/
private void threadPoolExecutorTest4() throws Exception {
/**
* SynchronousQueue,實際上它不是一個真正的隊列,因為它不會為隊列中元素維護存儲空間。與其他隊列不同的是,它維護一組線程,這些線程在等待著把元素加入或移出隊列。
* 在使用SynchronousQueue作為工作隊列的前提下,客戶端代碼向線程池提交任務時, 而線程池中又沒有空閑的線程能夠從SynchronousQueue隊列實例中取一個任務,
* 那么相應的offer方法調(diào)用就會失?。慈蝿諞]有被存入工作隊列)。此時,ThreadPoolExecutor會新建一個新的工作者線程用于對這個入隊列失敗的任務進行處理
* (假設(shè)此時線程池的大小還未達到其最大線程池大小maximumPoolSize)。
*/
// 和Executors.newCachedThreadPool()一樣的
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(
0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue());
testCommon(threadPoolExecutor);
// 預計結(jié)果:
// 1、 線程池線程數(shù)量為:15,超出數(shù)量的任務,其他的進入隊列中等待被執(zhí)行
// 2、 所有任務執(zhí)行結(jié)束,60秒后,如果無任務可執(zhí)行,所有線程全部被銷毀,池的大小恢復為0
Thread.sleep(60000L);
System.out.println("60秒后,再看線程池中的數(shù)量:" + threadPoolExecutor.getPoolSize());
}
/**
* 5、 定時執(zhí)行線程池信息:3秒后執(zhí)行,一次性任務,到點就執(zhí)行
* 核心線程數(shù)量5,最大數(shù)量Integer.MAX_VALUE,DelayedWorkQueue延時隊列,超出核心線程數(shù)量的線程存活時間:0秒
*
* @throws Exception
*/
private void threadPoolExecutorTest5() throws Exception {
// 和Executors.newScheduledThreadPool()一樣的
ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
threadPoolExecutor.schedule(
new Runnable() {
@Override
public void run() {
System.out.println("任務被執(zhí)行,現(xiàn)在時間:" + System.currentTimeMillis());
}
},
3000,
TimeUnit.MILLISECONDS);
System.out.println(
"定時任務,提交成功,時間是:"
+ System.currentTimeMillis()
+ ", 當前線程池中線程數(shù)量:"
+ threadPoolExecutor.getPoolSize());
// 預計結(jié)果:任務在3秒后被執(zhí)行一次
}
/**
* 6、 定時執(zhí)行線程池信息:線程固定數(shù)量5 ,
* 核心線程數(shù)量5,最大數(shù)量Integer.MAX_VALUE,DelayedWorkQueue延時隊列,超出核心線程數(shù)量的線程存活時間:0秒
*
* @throws Exception
*/
private void threadPoolExecutorTest6() throws Exception {
ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
/**
* 周期性執(zhí)行某一個任務,線程池提供了兩種調(diào)度方式,這里單獨演示一下。測試場景一樣。測試場景:提交的任務需要3秒才能執(zhí)行完畢??磧煞N不同調(diào)度方式的區(qū)別 效果1:
* 提交后,2秒后開始第一次執(zhí)行,之后每間隔1秒,固定執(zhí)行一次(如果發(fā)現(xiàn)上次執(zhí)行還未完畢,則等待完畢,完畢后立刻執(zhí)行)。
* 也就是說這個代碼中是,3秒鐘執(zhí)行一次(計算方式:每次執(zhí)行三秒,間隔時間1秒,執(zhí)行結(jié)束后馬上開始下一次執(zhí)行,無需等待)
*/
threadPoolExecutor.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任務-1 被執(zhí)行,現(xiàn)在時間:" + System.currentTimeMillis());
}
},
2000,
1000,
TimeUnit.MILLISECONDS);
/**
* 效果2:提交后,2秒后開始第一次執(zhí)行,之后每間隔1秒,固定執(zhí)行一次(如果發(fā)現(xiàn)上次執(zhí)行還未完畢,則等待完畢,等上一次執(zhí)行完畢后再開始計時,等待1秒)。
* 也就是說這個代碼鐘的效果看到的是:4秒執(zhí)行一次。(計算方式:每次執(zhí)行3秒,間隔時間1秒,執(zhí)行完以后再等待1秒,所以是 3+1)
*/
threadPoolExecutor.scheduleWithFixedDelay(
new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任務-2 被執(zhí)行,現(xiàn)在時間:" + System.currentTimeMillis());
}
},
2000,
1000,
TimeUnit.MILLISECONDS);
}
private ThreadPoolExecutor testShutdownCommon() {
// 創(chuàng)建一個 核心線程數(shù)量為5,最大數(shù)量為10,等待隊列最大是3的線程池,也就是最大容納13個任務。
// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(
5,
10,
5,
TimeUnit.SECONDS,
new LinkedBlockingQueue(3),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("有任務被拒絕執(zhí)行了");
}
});
// 測試:提交15個執(zhí)行時間需要3秒的任務,看超過大小的2個,對應的處理情況
for (int i = 0; i < 15; i++) {
int n = i;
threadPoolExecutor.submit(
new Runnable() {
@Override
public void run() {
try {
System.out.println("開始執(zhí)行:" + n);
Thread.sleep(3000L);
System.err.println("執(zhí)行結(jié)束:" + n);
} catch (InterruptedException e) {
System.out.println("異常:" + e.getMessage());
}
}
});
System.out.println("任務提交成功 :" + i);
}
return threadPoolExecutor;
}
/**
* 7、 終止線程:線程池信息:核心線程數(shù)量5,最大數(shù)量10,隊列大小3,超出核心線程數(shù)量的線程存活時間:5秒, 指定拒絕策略的
*
* @throws Exception
*/
private void threadPoolExecutorTest7() throws Exception {
ThreadPoolExecutor threadPoolExecutor = testShutdownCommon();
// 1秒后終止線程池
Thread.sleep(1000L);
threadPoolExecutor.shutdown();
// 再次提交提示失敗
threadPoolExecutor.submit(
new Runnable() {
@Override
public void run() {
System.out.println("追加一個任務");
}
});
// 結(jié)果分析
// 1、 10個任務被執(zhí)行,3個任務進入隊列等待,2個任務被拒絕執(zhí)行
// 2、調(diào)用shutdown后,不接收新的任務,等待13任務執(zhí)行結(jié)束
// 3、 追加的任務在線程池關(guān)閉后,無法再提交,會被拒絕執(zhí)行
}
/**
* 8、 立刻終止線程:線程池信息:核心線程數(shù)量5,最大數(shù)量10,隊列大小3,超出核心線程數(shù)量的線程存活時間:5秒, 指定拒絕策略的
*
* @throws Exception
*/
private void threadPoolExecutorTest8() throws Exception {
// 創(chuàng)建一個 核心線程數(shù)量為5,最大數(shù)量為10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
ThreadPoolExecutor threadPoolExecutor = testShutdownCommon();
// 1秒后終止線程池
Thread.sleep(1000L);
List shutdownNow = threadPoolExecutor.shutdownNow();
// 再次提交提示失敗
threadPoolExecutor.submit(
new Runnable() {
@Override
public void run() {
System.out.println("追加一個任務");
}
});
System.out.println("未結(jié)束的任務有:" + shutdownNow.size());
// 結(jié)果分析
// 1、 10個任務被執(zhí)行,3個任務進入隊列等待,2個任務被拒絕執(zhí)行
// 2、調(diào)用shutdownnow后,隊列中的3個線程不再執(zhí)行,10個線程被終止
// 3、 追加的任務在線程池關(guān)閉后,無法再提交,會被拒絕執(zhí)行
}
public static void main(String[] args) throws Exception {
Demo7 demo7 = new Demo7();
// demo7.threadPoolExecutorTest1();
// demo7.threadPoolExecutorTest2();
// demo7.threadPoolExecutorTest3();
// demo7.threadPoolExecutorTest4();
// demo7.threadPoolExecutorTest5();
// demo7.threadPoolExecutorTest6();
// demo7.threadPoolExecutorTest7();
demo7.threadPoolExecutorTest8();
}
}
關(guān)于線程池的實現(xiàn)原理是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。