模擬簡單Java線程池的方法詳解
一、 前言
為了實現(xiàn)并發(fā)編程,于是就引入了進(jìn)程這個概念。進(jìn)程就相當(dāng)于操作系統(tǒng)的一個任務(wù)。多個進(jìn)程同時執(zhí)行任務(wù),就實現(xiàn)了并發(fā)編程,能夠更快的執(zhí)行。
但是由于進(jìn)程還不夠輕量,創(chuàng)建一個進(jìn)程,銷毀一個進(jìn)程消耗的資源不可忽視。如果進(jìn)程數(shù)量不多的情況下,這些資源消耗是可以接受的,但是如果頻繁的創(chuàng)建、銷毀進(jìn)程。就是一筆很大的開銷了。
那要怎么辦呢?
為了解決這個問題,人們引入了更輕量的工具——線程。
線程也被稱為輕量級進(jìn)程。它的創(chuàng)建、銷毀比進(jìn)程消耗的資源更少。但是如果任務(wù)數(shù)量很多,多線程也頂不住頻繁的創(chuàng)建、銷毀了呢?這時線程池就出來解決問題了!
二、線程池是什么?
線程池是類似于Java字符串常量池一樣的東西。
使用線程VS不使用線程
- 當(dāng)使用一個線程的時候,就直接從池子里取一個線程過來。
- 當(dāng)不用一個線程的時候就把這個線程放到池子里
大家都知道找工作的流程大概是這樣的。
- 投簡歷
- 筆試
- 面試
- offer
當(dāng)我們到面試完了之后,會有兩種情況。
- 通過了,公司打電話通知你,給你發(fā)offer
- 沒通過,而且一般公司也不告訴你自己沒過,而是完全沒通知你沒有過,這是因為公司可能會把你放到他們的"人才貯備池"里了。
假設(shè)公司要找50個人,在秋招的時候,給50個人發(fā)了offer。 但是實際上,只有35個人來入職報道了。這時候,剩下的15個人就從人才貯備池里直接撈出15個,直接發(fā)offer。
這時候可能過了一段時間,公司突然打電話通知你,你被錄用了,要不要來?這個操作就相當(dāng)于一個線程要被使用到了,直接從池子里拿出來用。
這就是用找工作的例子形容了一下線程池大概是什么意思。
三、線程池構(gòu)造方法ThreadPoolExecutor的構(gòu)造方法的參數(shù)都是啥意思?
在《阿里巴巴java開發(fā)手冊》中指出了線程資源必須通過線程池提供,不允許在應(yīng)用中自行顯示的創(chuàng)建線程,這樣一方面是線程的創(chuàng)建更加規(guī)范,可以合理控制開辟線程的數(shù)量;另一方面線程的細(xì)節(jié)管理交給線程池處理,優(yōu)化了資源的開銷。
"ThreadPoolExecutor"這個類是Java標(biāo)準(zhǔn)庫提供的一組類,用來使用線程池。
ThreadPoolExecutor的構(gòu)造方法有四個。分別含有不同的參數(shù),使用的場景也不同。
我們就以參數(shù)最多的構(gòu)造方法來介紹。
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor ( int corePoolSize, int maximumPoolSize , long keepAliveTime , TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler )
1.corePoolSize 核心線程數(shù)
2.maximumPoolSize 最大線程數(shù)
對于核心線程數(shù)和最大線程數(shù)可能不是很理解到底是干嘛的,這里舉一個員工上班的例子。
核心線程數(shù),就是公司里的正式員工,允許他們可以摸魚一會。 被發(fā)現(xiàn)了不至于開除。(相當(dāng)于線程池中的線程就算什么也不干也不會被銷毀)
最大線程數(shù),就是公司里的正式員工+臨時工組成的數(shù)量,但是這里的臨時工摸魚到了一定時間了就要被開除。(相當(dāng)于線程池中的線程被銷毀)
3.keepAliveTime 描述臨時工能摸魚多長時間的
4.unit 是一個時間單位,也就是keepAliveTime的單位。
5.workQueue 阻塞隊列,就組織了線程池要執(zhí)行的任務(wù)
6.threadFactory 線程的創(chuàng)建方式,通過這個參數(shù)來設(shè)定不同線程的創(chuàng)建方式
7.RejectedExecutionHandler handler 拒絕策略。當(dāng)任務(wù)隊列滿了的時候,新任務(wù)又來了,這時候咋辦?
(1):最新的任務(wù)不要了
(2):最老的任務(wù)不要了
(3):阻塞等待
(4)開擺:拋出異常
由于ThreadPoolExecutor使用起來比較復(fù)雜,最多有7個參數(shù)。標(biāo)準(zhǔn)庫為此又為程序員們提供了一組其他的類。相當(dāng)于對ThreadPoolExecutor又進(jìn)行了一層封裝。
1.newFixedThreadPool
:創(chuàng)建出一個固定線程數(shù)量的線程池。
ExecutorService Service1 = Executors.newFixedThreadPool (20);
2.newCachedThreadPool
:創(chuàng)建出一個數(shù)量可變的線程池
ExecutorService Service2 = Executors.newCachedThreadPool ();
3.newSingleThreadExecutor
:創(chuàng)建只有一個線程的線程池
ExecutorService Service3 = Executors.newSingleThreadExecutor ();
4.newScheduledThreadPool
:創(chuàng)建一個能設(shè)定延時時間的線程池。
ExecutorService Service4 = Executors.newScheduledThreadPool (20);
四、模擬實現(xiàn)一個線程池
模擬實現(xiàn)一個線程池的核心操作: .:將任務(wù)加到線程池中--submit。 .:使用Worker類描述一個工作線程,Runnable來描述一個任務(wù)。 .:創(chuàng)建一個BlockingQueue阻塞隊列組織所有任務(wù)。 .:每個Worker要做的事情就是不停的從阻塞隊列里獲取任務(wù)并執(zhí)行。 .:指定線程池中的線程最大數(shù)目,如果超過這個數(shù)目就不要再繼續(xù)創(chuàng)建線程了。
代碼實現(xiàn):
我們創(chuàng)建一個線程池并讓它不停的創(chuàng)建進(jìn)程打印hello
import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; /** * Created with IntelliJ IDEA. * * @Description: 模擬實現(xiàn)線程池的使用 */ public class ThreadDemo0327_2 { public static void main (String[] args) throws IOException, InterruptedException { ThreadPoll threadPoll=new ThreadPoll (); for (int i = 0 ; i <10 ; i++) { threadPoll.submit (new Runnable () { @Override public void run () { System.out.println ("hello"); } }); } } } class Worker extends Thread{ public BlockingQueue<Runnable> queue=null; public Worker(BlockingQueue<Runnable> queue){ this.queue=queue; } @Override public void run () { //工作線程的具體邏輯 //需要從阻塞隊列中取任務(wù). while (true){ try { Runnable command=queue.take (); //通過run來執(zhí)行具體任務(wù) command.run (); }catch (InterruptedException e){ e.printStackTrace (); } } } } class ThreadPoll{ //包含一個阻塞隊列,用來組織任務(wù) public BlockingQueue<Runnable> queue=new LinkedBlockingQueue<> (); //這個list就用來存放當(dāng)前的工作線程. public List<Thread> works=new ArrayList<> (); public int MAX_WORKER_COUNT=10; //通過這個方法,把任務(wù)加入到線程池中 //submit不光可以把任務(wù)放到阻塞隊列中,也可以負(fù)責(zé)創(chuàng)建線程 public void submit(Runnable command) throws IOException, InterruptedException { if(works.size ()<MAX_WORKER_COUNT){ //如果當(dāng)前工作線程的數(shù)量不足線程數(shù)目上線,就創(chuàng)建出新的線程 //工作線程就專門找一個類完成 //worker內(nèi)部要哦能夠取到隊列的內(nèi)容,就要把這個隊列實例通過worker的構(gòu)造方法傳過去 Worker worker=new Worker (queue); worker.start (); works.add (worker); } queue.put (command); } }
運(yùn)行效果:
可以看到,打印了10個hello。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringMVC?RESTFul實戰(zhàn)案例修改功能實現(xiàn)
這篇文章主要為大家介紹了SpringMVC?RESTFul實戰(zhàn)案例修改功能實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05SpringSecurity自定義資源攔截規(guī)則及登錄界面跳轉(zhuǎn)問題
這篇文章主要介紹了SpringSecurity自定義資源攔截規(guī)則及登錄界面跳轉(zhuǎn)問題,我們想要自定義認(rèn)證邏輯,就需要創(chuàng)建一些原來不存在的bean,這個時候就可以使@ConditionalOnMissingBean注解,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-12-12springboot使用hibernate validator校驗方式
hibernate validator提供了一套比較完善、便捷的驗證實現(xiàn)方式。下面小編給大家介紹下springboot使用hibernate validator校驗方式,感興趣的朋友一起看看吧2018-01-01Java開發(fā)學(xué)習(xí)之Bean的生命周期詳解
從創(chuàng)建到消亡的完整過程,例如人從出生到死亡的整個過程就是一個生命周期。本文將通過示例為大家詳細(xì)講講Bean的生命周期,感興趣的可以學(xué)習(xí)一下2022-06-06java 中序列化NotSerializableException問題解決辦法
這篇文章主要介紹了java 中序列化NotSerializableException問題解決辦法的相關(guān)資料,這里對序列化問題進(jìn)行描述說明,并提供解決辦法,希望能幫助到大家,需要的朋友可以參考下2017-08-08IDEA全量替換一次性解決舊項目并將所有文件換行符改為LF問題
這篇文章主要介紹了IDEA全量替換一次性解決舊項目并將所有文件換行符改為LF問題,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下2019-05-05Java遍歷輸出指定目錄、樹形結(jié)構(gòu)所有文件包括子目錄下的文件
這篇文章主要介紹了Java遍歷輸出指定目錄、樹形結(jié)構(gòu)下的所有文件包括子目錄中的文件,需要的朋友可以參考下2015-07-07