中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

java虛擬機(jī)多線程知識(shí)點(diǎn)有哪些

這篇文章主要講解了“java虛擬機(jī)多線程知識(shí)點(diǎn)有哪些”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“java虛擬機(jī)多線程知識(shí)點(diǎn)有哪些”吧!

你所需要的網(wǎng)站建設(shè)服務(wù),我們均能行業(yè)靠前的水平為你提供.標(biāo)準(zhǔn)是產(chǎn)品質(zhì)量的保證,主要從事網(wǎng)站制作、做網(wǎng)站、企業(yè)網(wǎng)站建設(shè)、成都手機(jī)網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì)、成都品牌網(wǎng)站建設(shè)、網(wǎng)頁(yè)制作、做網(wǎng)站、建網(wǎng)站。創(chuàng)新互聯(lián)公司擁有實(shí)力堅(jiān)強(qiáng)的技術(shù)研發(fā)團(tuán)隊(duì)及素養(yǎng)的視覺(jué)設(shè)計(jì)專(zhuān)才。

1.線程池基本參數(shù)

以Executors.newFixedThreadPool()這種創(chuàng)建方式為例:

大家想象,假如你創(chuàng)建一個(gè)線程池,你想這個(gè)池子有些什么參數(shù)呢?首先這個(gè)池子必須要有一個(gè)最大值;然后還希望這個(gè)池子的線程數(shù)量有一個(gè)警戒線,到了這個(gè)警戒線的位置說(shuō)明線程池暫時(shí)已經(jīng)滿了,如果這個(gè)時(shí)候還有人過(guò)來(lái)拿線程,我們就要把這些人抓起來(lái)扔到一個(gè)地方去讓他們排隊(duì),告訴他們:請(qǐng)稍等,等我們的線程有空閑的時(shí)候再來(lái)處理你的事;再然后假如人排隊(duì)的地方都滿了,瑪?shù)?,好多人,于是線程池就想辦法東拼西湊又多搞出來(lái)了幾個(gè)線程去處理了;最后,假如那搞出來(lái)的這幾個(gè)線程還是不夠用,并且排隊(duì)的地方總是滿的,于是線程池生氣了,就這么多人可以了,如果還有人過(guò)來(lái)的趕緊讓它滾蛋;

這里我們需要知道幾個(gè)東西:

1這里的警戒線叫做核心線程池大?。╟orePoolSize);

2.最大值還是叫做線程池線程最大數(shù)量(maximumPoolSize)

3.排隊(duì)的地方叫做隊(duì)列(BlockingQueue<Runnable> ),這個(gè)隊(duì)列用于保存我們的線程要做的任務(wù),這個(gè)隊(duì)列有好幾種類(lèi)型,我們后面會(huì)分析的;

4.還有一個(gè)參數(shù)是keepAliveTime:線程存活時(shí)間,意思就是當(dāng)池中總共的線程大于核心線程池?cái)?shù)目,那就關(guān)閉池子中的空閑線程,要保證線程總數(shù)維持在核心線程池?cái)?shù)目或者之下;

現(xiàn)在我們來(lái)理一下邏輯:

池中當(dāng)前線程數(shù)量 <= 核心線程池大?。壕€程池直接創(chuàng)建線程處理

池中當(dāng)前線程數(shù)量 > 核心線程池?cái)?shù)量:將多余的任務(wù)放進(jìn)隊(duì)列

隊(duì)列滿了,還有任務(wù)過(guò)來(lái),線程池繼續(xù)創(chuàng)建線程,直到到達(dá)線程池最大數(shù)量

還有任務(wù)過(guò)來(lái),這里會(huì)有一個(gè)飽和策略,默認(rèn)是直接丟棄繼續(xù)過(guò)來(lái)的任務(wù)

2.線程池種類(lèi)

我們上一節(jié)使用的線程池如下所示:

ExecutorService pool = Executors.newFixedThreadPool(3);pool.execute(new RunnableImpl("玩游戲"));

我們是通過(guò)Executors這個(gè)類(lèi)的靜態(tài)方法創(chuàng)建的一個(gè)線程池,于是進(jìn)入這個(gè)類(lèi)我們看看這個(gè)類(lèi)還有沒(méi)有創(chuàng)建其他種類(lèi)線程池的方法,居然還真有。。。

我們先簡(jiǎn)單說(shuō)說(shuō)這四種分別是干嘛用的;

newFixedThreadPool(int):這個(gè)線程池就是上面說(shuō)的那種方式,也是我們重點(diǎn)要看源碼的線程池;

newSingThreadExecutor():這個(gè)不能說(shuō)是線程池了,因?yàn)槔锩孢@里面只有一個(gè)線程,而且自帶一個(gè)隊(duì)列,只要有任務(wù)來(lái)了就會(huì)把任務(wù)保存到隊(duì)列中,然后這個(gè)線程就慢慢的一個(gè)一個(gè)執(zhí)行。

newCachedThreadPool():無(wú)限線程的線程池

newScheduledThreadPool(int):一個(gè)定時(shí)的線程池,可以讓線程池中的線程延遲指定時(shí)間再執(zhí)行任務(wù);

3.Executors繼承結(jié)構(gòu)

我們可以看到實(shí)際上實(shí)例化的是一個(gè)ThreadPoolExecutor對(duì)象,這個(gè)對(duì)象作用是用線程去處理傳進(jìn)去的任務(wù):

我們看一下這個(gè)繼承結(jié)構(gòu),

Executor接口:只是定義了execute();這個(gè)方法,等待子類(lèi)去實(shí)現(xiàn);

ExecutorService接口:繼承Execute接口,并又聲明了shutdown()方法和submit()方法,等待子類(lèi)去實(shí)現(xiàn)

AbstractExecutorService抽象類(lèi):初步實(shí)現(xiàn)了submit()方法,但是內(nèi)部調(diào)用的execute()方法去執(zhí)行任務(wù)

ThreadPoolExecutor類(lèi):這個(gè)類(lèi)是實(shí)現(xiàn)了很多的方法,將shutdown()和execute()方法都給實(shí)現(xiàn)了;

4.看看execute()方法源碼

下面我們主要就是看看execute()方法的內(nèi)部是怎么實(shí)現(xiàn)的,知道了這個(gè)的實(shí)現(xiàn)原理也就差不多了 

public void execute(Runnable command) {  if (command == null)   throw new NullPointerException();   int c = ctl.get();    //workCountOf(c)表示當(dāng)前線程池中線程的數(shù)量;這里進(jìn)行一個(gè)判斷,當(dāng)線程池中線程數(shù)目小于核心池子數(shù)目時(shí),  就調(diào)用addWorker()方法將我們的任務(wù)添加進(jìn)去,等下可以看到addWorker()方法內(nèi)部其實(shí)就是創(chuàng)建線程并處理請(qǐng)求,  就類(lèi)似new Thread(xxx).start()這種方式     if (workerCountOf(c) < corePoolSize) {   if (addWorker(command, true))    return;   c = ctl.get();  }//如果當(dāng)前線程數(shù)目大于核心線程并且任務(wù)放入一個(gè)隊(duì)列成功,內(nèi)部還會(huì)再次進(jìn)行線程池狀態(tài)判斷,這里的&&用得比較精髓(短路作用),好好體會(huì)一下,  假如不是運(yùn)行狀態(tài)那就會(huì)執(zhí)行remove方法 刪除隊(duì)列中的任務(wù),如果是運(yùn)行狀態(tài)直接進(jìn)入else if,這里的目的是線程池中已經(jīng)關(guān)閉了,我們添加一個(gè)null任務(wù)  表示線程池不再處理任務(wù)      if (isRunning(c) && workQueue.offer(command)) {   int recheck = ctl.get();   if (! isRunning(recheck) && remove(command))    reject(command);   else if (workerCountOf(recheck) == 0)    addWorker(null, false);  }//能執(zhí)行到這里,說(shuō)明上面兩個(gè)if中的條件都不滿足,條件應(yīng)該是:當(dāng)前線程大于核心線程,并且向隊(duì)列中添加任務(wù)失敗,換句說(shuō)說(shuō)就是對(duì)列已經(jīng)滿了,裝不下這么多任務(wù)  于是我們r(jià)eject()方法內(nèi)部就是對(duì)這些多余的任務(wù)進(jìn)行處理的一些策略,默認(rèn)就是直接丟棄  else if (!addWorker(command, false))   reject(command); }

對(duì)于面這三種情況的判斷還是很清楚的,我們忽略很多細(xì)節(jié),因?yàn)槲覀兊哪康氖且獙?duì)整個(gè)邏輯有個(gè)大概的了解,而不是去完全消化這些源碼,這很不現(xiàn)實(shí),要想理解透徹只能慢慢的去研究...

我們來(lái)看看最重要的addWorker()這個(gè)方法,這個(gè)方法就是線程池將我們傳進(jìn)來(lái)的new Runnable(xxx)進(jìn)行處理,其實(shí)內(nèi)部就是用new Thread(xxxx).start()處理,只是出于線程池中會(huì)進(jìn)行很多的條件判斷以及將Runnable()做進(jìn)一步的封裝,我們了解就好,代碼如下:

private boolean addWorker(Runnable firstTask, boolean core) {  //這里刪除很多的條件判斷的代碼    ..........         boolean workerStarted = false;  boolean workerAdded = false;  Worker w = null;  try {   final ReentrantLock mainLock = this.mainLock;   //注意下面這兩行,其實(shí)就是將我們傳進(jìn)來(lái)的Runnable()進(jìn)行封裝成Worker,在Worker構(gòu)造器里面會(huì)new Thread()并且保存起來(lái)       這樣做的一個(gè)好處就是直接將一個(gè)線程和一個(gè)Runnable進(jìn)行綁定,我們隨時(shí)可以從Worker中獲取線程然后調(diào)用start()方法就ok了       w = new Worker(firstTask);   final Thread t = w.thread;   if (t != null) {    mainLock.lock();    try {     //此處刪除一些            .........     if (rs < SHUTDOWN ||      (rs == SHUTDOWN && firstTask == null)) {      if (t.isAlive()) // precheck that t is startable       throw new IllegalThreadStateException();

   //由于會(huì)有很多個(gè)Worker,于是我們會(huì)創(chuàng)建HashSet<Worker> workers = new HashSet<Worker>(),用于保存所有的worker,后續(xù)直接遍歷處理很方便              而且我們所說(shuō)的線程池的本質(zhì)就是這個(gè)workers,也就是一個(gè)HashSet              workers.add(w);               int s = workers.size();      if (s > largestPoolSize)       largestPoolSize = s;      workerAdded = true;     }    } finally {     mainLock.unlock();    }          //下面這個(gè)if語(yǔ)句中就是一個(gè)無(wú)限循環(huán)的去執(zhí)行線程的start()方法    if (workerAdded) {     t.start();     workerStarted = true;    }   }  }return workerStarted; }

說(shuō)出來(lái)你可能不信,我有點(diǎn)沒(méi)看懂這里,因?yàn)樽詈蟮哪莻€(gè)start()方法總感覺(jué)有點(diǎn)問(wèn)題,但是說(shuō)不上來(lái),你們覺(jué)得這個(gè)start()方法之后,CPU來(lái)運(yùn)行這個(gè)線程會(huì)執(zhí)行哪個(gè)run()方法?是我們傳進(jìn)去的類(lèi)的run()方法?還是worker的run()方法呢?

我們看看下面這兩行代碼,Worker構(gòu)造器中的新建線程的代碼就不截圖了,我們把下面這幾行代碼變化一下:

Worker w = new Worker(firstTask);final Thread t = w.thread;........t.start()

變化后:

Worker w = new Worker(firstTask);//firstTask是我們傳進(jìn)去的實(shí)現(xiàn)了Runnable接口的類(lèi),但是Worker也實(shí)現(xiàn)了Runnable接口 final Thread t = getThreadFactory().newThread(wt.start()

看到?jīng)]有,其實(shí)調(diào)用的是Worker的run()方法,然后在Worker的run()方法的內(nèi)部又會(huì)進(jìn)行很多處理,最后再去調(diào)用我們傳進(jìn)去的那個(gè)run()方法。5.總結(jié)  其實(shí)個(gè)人感覺(jué)深入到這里就差不多了,基本上就理解了線程池的流程,當(dāng)然有興趣的小伙伴可以繼續(xù)深入看看Worker中的run()方法是怎么執(zhí)行的,其實(shí)比較容易,主要是由很多對(duì)線程池很多狀態(tài)啊,線程數(shù)量等判斷可能會(huì)干擾我們的理解,如果后續(xù)有需要我們?cè)俾钊?,哈哈哈!  這一篇其實(shí)沒(méi)說(shuō)多少內(nèi)容,就是讓大家對(duì)線程池到底是個(gè)什么鬼有個(gè)最粗略的認(rèn)識(shí),其實(shí)本質(zhì)就是一個(gè)HashSet<Worker>,然后把我們創(chuàng)建的Runnable()實(shí)例先給封裝成Worker對(duì)象,其中Worker也是實(shí)現(xiàn)了Runnable接口,有點(diǎn)類(lèi)似裝飾者模式,哈哈!再之后就是將WOrker存到那個(gè)集合中,并且就調(diào)用start()方法調(diào)用worker的run()方法,然后最后可能就是調(diào)用我們傳進(jìn)去的那個(gè)run()方法了

感謝各位的閱讀,以上就是“java虛擬機(jī)多線程知識(shí)點(diǎn)有哪些”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)java虛擬機(jī)多線程知識(shí)點(diǎn)有哪些這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

標(biāo)題名稱(chēng):java虛擬機(jī)多線程知識(shí)點(diǎn)有哪些
文章網(wǎng)址:http://www.rwnh.cn/article18/gcgigp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、App開(kāi)發(fā)、服務(wù)器托管網(wǎng)站內(nèi)鏈、軟件開(kāi)發(fā)、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(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)

h5響應(yīng)式網(wǎng)站建設(shè)
张家川| 玛纳斯县| 华亭县| 石嘴山市| 合川市| 勐海县| 连城县| 金沙县| 赞皇县| 金寨县| 盐源县| 吉安县| 德保县| 太康县| 郓城县| 石门县| 台山市| 林州市| 汉阴县| 曲沃县| 安国市| 红原县| 图们市| 米易县| 巨野县| 德化县| 新晃| 新晃| 杂多县| 奉新县| 高邮市| 秭归县| 吴忠市| 交口县| 扎兰屯市| 深泽县| 鹤山市| 南澳县| 大余县| 鹿邑县| 乳山市|