這篇文章主要介紹“線程池主要參數(shù)有哪些”,在日常操作中,相信很多人在線程池主要參數(shù)有哪些問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”線程池主要參數(shù)有哪些”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括宿遷網(wǎng)站建設(shè)、宿遷網(wǎng)站制作、宿遷網(wǎng)頁(yè)制作以及宿遷網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,宿遷網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到宿遷省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!
線程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位,我們的程序最終都是由線程進(jìn)行運(yùn)作。在Java中,創(chuàng)建和銷(xiāo)毀線程的動(dòng)作是很消耗資源的,因此就出現(xiàn)了所謂“池化資源”技術(shù)。
線程池是池化資源技術(shù)的一個(gè)應(yīng)用,所謂線程池,顧名思義就是預(yù)先按某個(gè)規(guī)定創(chuàng)建若干個(gè)可執(zhí)行線程放入一個(gè)容器中(線程池),需要使用的時(shí)候從線程池中去取,用完之后不銷(xiāo)毀而是放回去,從而減少了線程創(chuàng)建和銷(xiāo)毀的次數(shù),達(dá)到節(jié)約資源的目的。
前面已經(jīng)講到線程池的出現(xiàn)減少了線程創(chuàng)建和銷(xiāo)毀的次數(shù),每個(gè)線程都可以被重復(fù)利用,可執(zhí)行多個(gè)任務(wù)。
每當(dāng)有任務(wù)到來(lái)時(shí),直接復(fù)用線程池中的線程,而不需要等待新線程的創(chuàng)建,這個(gè)動(dòng)作可以帶來(lái)響應(yīng)速度的提升
可以根據(jù)系統(tǒng)的承受能力,調(diào)整線程池中的工作線程的數(shù)量,防止因?yàn)榫€程過(guò)多服務(wù)器變慢或死機(jī)。java一個(gè)線程默認(rèn)占用空間為1M,可以想象一旦手動(dòng)創(chuàng)建線程過(guò)多極有可能導(dǎo)致內(nèi)存溢出。
我們可以用Executors類(lèi)來(lái)創(chuàng)建一些常用的線程池,但是像阿里是禁止直接通過(guò)Executors類(lèi)直接創(chuàng)建線程池的,具體的原因稍后再談。
在了解Executors類(lèi)所提供的幾個(gè)線程池前,我們首先來(lái)了解一下 ThreadPoolExecutor的主要參數(shù),ThreadPoolExecutor是創(chuàng)建線程池的類(lèi),我們選取參數(shù)最多的構(gòu)造方法來(lái)看一下:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
名稱(chēng) | 類(lèi)型 | 含義 |
---|---|---|
corePoolSize | int | 核心線程池的大小 |
maximumPoolSize | int | 最大線程池大小 |
keepAliveTime | long | 線程最大空閑時(shí)間 |
unit | TimeUnit | 時(shí)間單位 |
workQueue | BlockingQueue<Runnable> | 線程等待隊(duì)列 |
threadFactory | ThreadFactory | 線程創(chuàng)建工程 |
handler | RejectedExecutionHandler | 拒絕策略 |
當(dāng)向線程池提交一個(gè)任務(wù)時(shí),如果線程池中已創(chuàng)建的線程數(shù)量小于corePoolSIze,即便存在空閑線程,也會(huì)創(chuàng)建一個(gè)新線程來(lái)執(zhí)行任務(wù),直到創(chuàng)建的線程數(shù)大于或等于corePoolSIze。
線程池所允許的最大線程個(gè)數(shù),當(dāng)隊(duì)列滿(mǎn)了且已經(jīng)創(chuàng)建的線程數(shù)小于maximumPoolSize時(shí),會(huì)創(chuàng)建新的線程執(zhí)行任務(wù)。
當(dāng)線程中的線程數(shù)大于corePoolSIze時(shí),如果線程空閑時(shí)間大于keepAliveTime,該線程就會(huì)被銷(xiāo)毀。
keepAliveTime的時(shí)間單位
用于保存等待執(zhí)行任務(wù)的隊(duì)列
用于創(chuàng)建新線程。threadFactory創(chuàng)建的線程也是采用new Thread()方式,threadFactory創(chuàng)建的線程名都具有統(tǒng)一的風(fēng)格:pool-m-thread-n
拒絕策略,當(dāng)線程池和隊(duì)列滿(mǎn)了之后,再加入新線程后會(huì)執(zhí)行此策略。 下面是四種線程池的拒絕策略:
AbortPolicy:中斷任務(wù)并拋出異常
DiscardPolicy:中段任務(wù)但是不拋出異常
DiscardOldestPolicy:丟棄隊(duì)列中最老的任務(wù),然后嘗試提交新任務(wù)
CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
當(dāng)我們了解了ThreadPoolExecutor的七個(gè)參數(shù)后,我們就可以很快的理解線程池的流程:
當(dāng)提交任務(wù)后,首先判斷當(dāng)前線程數(shù)是否超過(guò)核心線程數(shù),如果沒(méi)超過(guò)則創(chuàng)建新線程執(zhí)行任務(wù),否則判斷工作隊(duì)列是否已滿(mǎn),如果未滿(mǎn)則將任務(wù)添加到隊(duì)列中,否則判斷線程數(shù)是否超過(guò)最大線程數(shù),如果未超過(guò)則創(chuàng)建線程執(zhí)行任務(wù),否則執(zhí)行拒絕策略。
executors提供了許多種線程池供用戶(hù)使用,雖然很多公司禁止使用executors創(chuàng)建線程池,但是對(duì)于剛開(kāi)始解除線程池的人來(lái)說(shuō),Executors類(lèi)所提供的線程池能很好的帶你進(jìn)入多線程的世界。
ExecutorService executorService = Executors.newSingleThreadExecutor();
聽(tīng)名字就可以知道這是一個(gè)單線程的線程池,在這個(gè)線程池中只有一個(gè)線程在工作,相當(dāng)于單線程執(zhí)行所有任務(wù),此線程可以保證所有任務(wù)的執(zhí)行順序按照提交順序執(zhí)行,看構(gòu)造方法也可以看出,corePoolSize和maximumPoolSize都是1。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
ExecutorService executorService = Executors.newFixedThreadPool(2);
固定長(zhǎng)度的線程池,線程池的長(zhǎng)度在創(chuàng)建時(shí)通過(guò)變量傳入。下面是newFixedThreadPool的構(gòu)造方法,corePoolSize和maximumPoolSize都是傳入的參數(shù)值
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
ExecutorService executorService = Executors.newCachedThreadPool();
可緩存線程池,這個(gè)線程池設(shè)定keepAliveTime為60秒,并且對(duì)最大線程數(shù)量幾乎不做控制。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
觀察構(gòu)造方法,corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即線程數(shù)量幾乎無(wú)限制。設(shè)定keepAliveTime 為60秒,線程空閑60秒后自動(dòng)結(jié)束,因?yàn)樵摼€程池創(chuàng)建無(wú)限制,不會(huì)有隊(duì)列等待,所以使用SynchronousQueue同步隊(duì)列。
創(chuàng)建一個(gè)定時(shí)的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。下面是newScheduledThreadPool的用法:
Thread thread1=new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"thread1"); } }); Thread thread2=new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"thread2"); } }); Thread thread3=new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"thread3"); } }); ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); //在1000ms后執(zhí)行thread1 scheduledExecutorService.schedule(thread1,1000,TimeUnit.MILLISECONDS); //在1000ms后每隔1000ms執(zhí)行一次thread2,如果任務(wù)執(zhí)行時(shí)間比間隔時(shí)間長(zhǎng),則延遲執(zhí)行 scheduledExecutorService.scheduleAtFixedRate(thread2,1000,1000,TimeUnit.MILLISECONDS); //和第二種方式類(lèi)似,但下一次任務(wù)開(kāi)始的時(shí)間為:上一次任務(wù)結(jié)束時(shí)間(而不是開(kāi)始時(shí)間) + delay時(shí)間 scheduledExecutorService.scheduleWithFixedDelay(thread3,1000,1000,TimeUnit.MILLISECONDS);
如果你的idea裝了Alibaba Java Codeing Guidelines插件(推薦大家使用,有助于讓你的代碼更加規(guī)范),那么當(dāng)你寫(xiě)了Exectors創(chuàng)建線程池后會(huì)看到提示:
并且阿里將這個(gè)用法定義為Blocker,即不允許使用,而是讓人們用ThreadPoolExecutor的方式創(chuàng)建線程池。原因是通過(guò)ThreadPoolExecutor的方式,這樣的處理方式讓寫(xiě)的人更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)。
Executors返回的線程池對(duì)象的弊端如下:
1)FixedThreadPool和SingleThreadPool:
??允許的請(qǐng)求隊(duì)列長(zhǎng)度為Integer.MAX_VALUE,可能會(huì)堆積大量的請(qǐng)求,從而導(dǎo)致OOM。 ?? 2)CachedThreadPool:
??允許的創(chuàng)建線程數(shù)量為Integer.MAX_VALUE,可能會(huì)創(chuàng)建大量的線程,從而導(dǎo)致OOM。 ?? 下面是ThreadPoolExecutor創(chuàng)建線程池的簡(jiǎn)單例子
int corePoolSize=5; int maximumPoolSize=10; long keepAliveTime=30; BlockingQueue<Runnable> blockingQueue=new ArrayBlockingQueue(2); RejectedExecutionHandler handler=new ThreadPoolExecutor.AbortPolicy(); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, blockingQueue, handler); threadPoolExecutor.execute(thread1);
SpringBoot對(duì)線程池又做了一層封裝,在SpringBoot中,可以通過(guò)ThreadPoolTaskExecutor類(lèi)來(lái)創(chuàng)建線程池。需要注意兩者的區(qū)別ThreadPoolExecutor時(shí)JUC包下的類(lèi),ThreadPoolTaskExecutor是springframework包下的類(lèi)。但原理都是一樣的。
首先搭建一個(gè)SpringBoot項(xiàng)目,只需要引入web依賴(lài)即可
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
線程池的參數(shù)盡量寫(xiě)到配置文件里,這樣就能根據(jù)需要進(jìn)行修改,在application.properties文件中配置:
myExecutor.corePoolSize=5 myExecutor.maxPoolSize=10 myExecutor.keepAliveSeconds=30 myExecutor.allowCoreThreadTimeOut=false myExecutor.queueCapacity=20 myExecutor.threadNamePrefix=myExecutor-
新建一個(gè)包叫config,新建類(lèi)ExecutorConfig ,首先參數(shù)的值從配置文件中獲取,接著用ThreadPoolTaskExecutor 創(chuàng)建一個(gè)自己的線程池,注入到Bean容器中。
@Configuration @EnableAsync public class ExecutorConfig { @Value("${myExecutor.corePoolSize}") private int corePoolSize; @Value("${myExecutor.maxPoolSize}") private int maxPoolSize; @Value("${myExecutor.keepAliveSeconds}") private int keepAliveSeconds; @Value("${myExecutor.allowCoreThreadTimeOut}") private boolean allowCoreThreadTimeOut; @Value("${myExecutor.queueCapacity}") private int queueCapacity; @Value("${myExecutor.threadNamePrefix}") private String threadNamePrefix; @Bean("myExecutor") public Executor myExecutor(){ ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor(); //核心線程數(shù) executor.setCorePoolSize(corePoolSize); //最大線程數(shù) executor.setMaxPoolSize(maxPoolSize); //線程空閑時(shí)間 executor.setKeepAliveSeconds(keepAliveSeconds); //是否保留核心線程數(shù) executor.setAllowCoreThreadTimeOut(allowCoreThreadTimeOut); //隊(duì)列長(zhǎng)度 executor.setQueueCapacity(queueCapacity); //拒絕策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); //設(shè)置線程名稱(chēng)前綴 executor.setThreadNamePrefix(threadNamePrefix); executor.initialize(); return executor; } }
這里需要注意的是有一個(gè)方法setAllowCoreThreadTimeOut,當(dāng)傳入?yún)?shù)為true時(shí),所有線程超時(shí)后都會(huì)被銷(xiāo)毀,如果為false,只有超過(guò)核心線程數(shù)并且超時(shí)時(shí)才會(huì)被銷(xiāo)毀。
首先寫(xiě)一個(gè)service接口:
public interface DoSomeThing { /** * 通過(guò)線程池異步執(zhí)行耗時(shí)的任務(wù) */ public void doSomeThing(); }
再編寫(xiě)實(shí)現(xiàn)類(lèi):
@Service public class DoSomeThingImpl implements DoSomeThing { @Override @Async("myExecutor") public void doSomeThing() { System.out.println(Thread.currentThread().getName()+"-in"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-out"); } }
增加注解@Async("myExecutor")后,這段方法就會(huì)異步由myExecutor線程池執(zhí)行。
新建一個(gè)IndexController,每次請(qǐng)求執(zhí)行一次doSomeThing()方法。
@RestController public class IndexController { @Autowired private DoSomeThing doSomeThing; @RequestMapping(value = "/index",method = RequestMethod.GET) public String index(){ doSomeThing.doSomeThing(); return "success"; } }
訪問(wèn)十次http://localhost:8080/index,由于設(shè)置的核心線程數(shù)是5,隊(duì)列容量是30,因此最多只會(huì)用到5個(gè)線程資源,結(jié)果如下:
到此,關(guān)于“線程池主要參數(shù)有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
當(dāng)前文章:線程池主要參數(shù)有哪些
當(dāng)前鏈接:http://jinyejixie.com/article42/jpcohc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、網(wǎng)站策劃、App設(shè)計(jì)、用戶(hù)體驗(yàn)、網(wǎng)站設(shè)計(jì)公司、定制開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
網(wǎng)頁(yè)設(shè)計(jì)公司知識(shí)