91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java虛擬機多線程知識點有哪些

發布時間:2021-11-19 16:15:34 來源:億速云 閱讀:147 作者:iii 欄目:編程語言

這篇文章主要講解了“java虛擬機多線程知識點有哪些”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“java虛擬機多線程知識點有哪些”吧!

1.線程池基本參數

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

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

這里我們需要知道幾個東西:

1這里的警戒線叫做核心線程池大小(corePoolSize);

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

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

4.還有一個參數是keepAliveTime:線程存活時間,意思就是當池中總共的線程大于核心線程池數目,那就關閉池子中的空閑線程,要保證線程總數維持在核心線程池數目或者之下;

現在我們來理一下邏輯:

池中當前線程數量 <= 核心線程池大小:線程池直接創建線程處理

池中當前線程數量 > 核心線程池數量:將多余的任務放進隊列

隊列滿了,還有任務過來,線程池繼續創建線程,直到到達線程池最大數量

還有任務過來,這里會有一個飽和策略,默認是直接丟棄繼續過來的任務

2.線程池種類

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

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

我們是通過Executors這個類的靜態方法創建的一個線程池,于是進入這個類我們看看這個類還有沒有創建其他種類線程池的方法,居然還真有。。。

我們先簡單說說這四種分別是干嘛用的;

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

newSingThreadExecutor():這個不能說是線程池了,因為里面這里面只有一個線程,而且自帶一個隊列,只要有任務來了就會把任務保存到隊列中,然后這個線程就慢慢的一個一個執行。

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

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

3.Executors繼承結構

我們可以看到實際上實例化的是一個ThreadPoolExecutor對象,這個對象作用是用線程去處理傳進去的任務:

我們看一下這個繼承結構,

Executor接口:只是定義了execute();這個方法,等待子類去實現;

ExecutorService接口:繼承Execute接口,并又聲明了shutdown()方法和submit()方法,等待子類去實現

AbstractExecutorService抽象類:初步實現了submit()方法,但是內部調用的execute()方法去執行任務

ThreadPoolExecutor類:這個類是實現了很多的方法,將shutdown()和execute()方法都給實現了;

4.看看execute()方法源碼

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

public void execute(Runnable command) {  if (command == null)   throw new NullPointerException();   int c = ctl.get();    //workCountOf(c)表示當前線程池中線程的數量;這里進行一個判斷,當線程池中線程數目小于核心池子數目時,  就調用addWorker()方法將我們的任務添加進去,等下可以看到addWorker()方法內部其實就是創建線程并處理請求,  就類似new Thread(xxx).start()這種方式     if (workerCountOf(c) < corePoolSize) {   if (addWorker(command, true))    return;   c = ctl.get();  }//如果當前線程數目大于核心線程并且任務放入一個隊列成功,內部還會再次進行線程池狀態判斷,這里的&&用得比較精髓(短路作用),好好體會一下,  假如不是運行狀態那就會執行remove方法 刪除隊列中的任務,如果是運行狀態直接進入else if,這里的目的是線程池中已經關閉了,我們添加一個null任務  表示線程池不再處理任務      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);  }//能執行到這里,說明上面兩個if中的條件都不滿足,條件應該是:當前線程大于核心線程,并且向隊列中添加任務失敗,換句說說就是對列已經滿了,裝不下這么多任務  于是我們reject()方法內部就是對這些多余的任務進行處理的一些策略,默認就是直接丟棄  else if (!addWorker(command, false))   reject(command); }

對于面這三種情況的判斷還是很清楚的,我們忽略很多細節,因為我們的目的是要對整個邏輯有個大概的了解,而不是去完全消化這些源碼,這很不現實,要想理解透徹只能慢慢的去研究...

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

private boolean addWorker(Runnable firstTask, boolean core) {  //這里刪除很多的條件判斷的代碼    ..........         boolean workerStarted = false;  boolean workerAdded = false;  Worker w = null;  try {   final ReentrantLock mainLock = this.mainLock;   //注意下面這兩行,其實就是將我們傳進來的Runnable()進行封裝成Worker,在Worker構造器里面會new Thread()并且保存起來       這樣做的一個好處就是直接將一個線程和一個Runnable進行綁定,我們隨時可以從Worker中獲取線程然后調用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();

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

說出來你可能不信,我有點沒看懂這里,因為最后的那個start()方法總感覺有點問題,但是說不上來,你們覺得這個start()方法之后,CPU來運行這個線程會執行哪個run()方法?是我們傳進去的類的run()方法?還是worker的run()方法呢?

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

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

變化后:  

Worker w = new Worker(firstTask);//firstTask是我們傳進去的實現了Runnable接口的類,但是Worker也實現了Runnable接口 final Thread t = getThreadFactory().newThread(wt.start()

看到沒有,其實調用的是Worker的run()方法,然后在Worker的run()方法的內部又會進行很多處理,最后再去調用我們傳進去的那個run()方法。5.總結  其實個人感覺深入到這里就差不多了,基本上就理解了線程池的流程,當然有興趣的小伙伴可以繼續深入看看Worker中的run()方法是怎么執行的,其實比較容易,主要是由很多對線程池很多狀態啊,線程數量等判斷可能會干擾我們的理解,如果后續有需要我們再慢慢深入,哈哈哈!  這一篇其實沒說多少內容,就是讓大家對線程池到底是個什么鬼有個最粗略的認識,其實本質就是一個HashSet<Worker>,然后把我們創建的Runnable()實例先給封裝成Worker對象,其中Worker也是實現了Runnable接口,有點類似裝飾者模式,哈哈!再之后就是將WOrker存到那個集合中,并且就調用start()方法調用worker的run()方法,然后最后可能就是調用我們傳進去的那個run()方法了

感謝各位的閱讀,以上就是“java虛擬機多線程知識點有哪些”的內容了,經過本文的學習后,相信大家對java虛擬機多線程知識點有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

临城县| 独山县| 曲麻莱县| 老河口市| 景泰县| 岫岩| 兴宁市| 罗江县| 清涧县| 呼伦贝尔市| 双峰县| 营口市| 班玛县| 农安县| 师宗县| 乡宁县| 沂源县| 色达县| 外汇| 乾安县| 新兴县| 古浪县| 桃园县| 大宁县| 灵丘县| 岱山县| 远安县| 冷水江市| 马龙县| 泸定县| 老河口市| 洛阳市| 尉氏县| 静乐县| 民勤县| 通城县| 海兴县| 南岸区| 临海市| 三穗县| 合肥市|