① java 線程池 工作隊列是如何工作的
使用線程池的好處
1、降低資源消耗
可以重復利用已創建的線程降低線程創建和銷毀造成的消耗。
2、提高響應速度
當任務到達時,任務可以不需要等到線程創建就能立即執行。
3、提高線程的可管理性
線程是稀缺資源,如果無限制地創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一分配、調優和監控
線程池的工作原理
首先我們看下當一個新的任務提交到線程池之後,線程池是如何處理的
1、線程池判斷核心線程池裡的線程是否都在執行任務。如果不是,則創建一個新的工作線程來執行任務。如果核心線程池裡的線程都在執行任務,則執行第二步。
2、線程池判斷工作隊列是否已經滿。如果工作隊列沒有滿,則將新提交的任務存儲在這個工作隊列里進行等待。如果工作隊列滿了,則執行第三步
3、線程池判斷線程池的線程是否都處於工作狀態。如果沒有,則創建一個新的工作線程來執行任務。如果已經滿了,則交給飽和策略來處理這個任務
線程池飽和策略
這里提到了線程池的飽和策略,那我們就簡單介紹下有哪些飽和策略:
AbortPolicy
為Java線程池默認的阻塞策略,不執行此任務,而且直接拋出一個運行時異常,切記ThreadPoolExecutor.execute需要try catch,否則程序會直接退出。
DiscardPolicy
直接拋棄,任務不執行,空方法
DiscardOldestPolicy
從隊列裡面拋棄head的一個任務,並再次execute 此task。
CallerRunsPolicy
在調用execute的線程裡面執行此command,會阻塞入口
用戶自定義拒絕策略(最常用)
實現RejectedExecutionHandler,並自己定義策略模式
下我們以ThreadPoolExecutor為例展示下線程池的工作流程圖
3.jpg
關鍵方法源碼分析
我們看看核心方法添加到線程池方法execute的源碼如下:
// //Executes the given task sometime in the future. The task //may execute in a new thread or in an existing pooled thread. // // If the task cannot be submitted for execution, either because this // executor has been shutdown or because its capacity has been reached, // the task is handled by the current {@code RejectedExecutionHandler}. // // @param command the task to execute // @throws RejectedExecutionException at discretion of // {@code RejectedExecutionHandler}, if the task // cannot be accepted for execution // @throws NullPointerException if {@code command} is null // public void execute(Runnable command) { if (command == null) throw new NullPointerException(); // // Proceed in 3 steps: // // 1. If fewer than corePoolSize threads are running, try to // start a new thread with the given command as its first // task. The call to addWorker atomically checks runState and // workerCount, and so prevents false alarms that would add // threads when it shouldn't, by returning false. // 翻譯如下: // 判斷當前的線程數是否小於corePoolSize如果是,使用入參任務通過addWord方法創建一個新的線程, // 如果能完成新線程創建exexute方法結束,成功提交任務 // 2. If a task can be successfully queued, then we still need // to double-check whether we should have added a thread // (because existing ones died since last checking) or that // the pool shut down since entry into this method. So we // recheck state and if necessary roll back the enqueuing if // stopped, or start a new thread if there are none. // 翻譯如下: // 在第一步沒有完成任務提交;狀態為運行並且能否成功加入任務到工作隊列後,再進行一次check,如果狀態 // 在任務加入隊列後變為了非運行(有可能是在執行到這里線程池shutdown了),非運行狀態下當然是需要 // reject;然後再判斷當前線程數是否為0(有可能這個時候線程數變為了0),如是,新增一個線程; // 3. If we cannot queue task, then we try to add a new // thread. If it fails, we know we are shut down or saturated // and so reject the task. // 翻譯如下: // 如果不能加入任務到工作隊列,將嘗試使用任務新增一個線程,如果失敗,則是線程池已經shutdown或者線程池 // 已經達到飽和狀態,所以reject這個他任務 // int c = ctl.get(); // 工作線程數小於核心線程數 if (workerCountOf(c) < corePoolSize) { // 直接啟動新線程,true表示會再次檢查workerCount是否小於corePoolSize if (addWorker(command, true)) return; c = ctl.get(); } // 如果工作線程數大於等於核心線程數 // 線程的的狀態未RUNNING並且隊列notfull if (isRunning(c) && workQueue.offer(command)) { // 再次檢查線程的運行狀態,如果不是RUNNING直接從隊列中移除 int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) // 移除成功,拒絕該非運行的任務 reject(command); else if (workerCountOf(recheck) == 0) // 防止了SHUTDOWN狀態下沒有活動線程了,但是隊列里還有任務沒執行這種特殊情況。 // 添加一個null任務是因為SHUTDOWN狀態下,線程池不再接受新任務 addWorker(null, false); } // 如果隊列滿了或者是非運行的任務都拒絕執行 else if (!addWorker(command, false)) reject(command); }
② 什麼是java線程池
多線程是為了能夠讓計算機資源合理的分配,對於處理不同的任務創建不同的線程進行處理,但是計算機創建一個線程或者銷毀一個線程所花費的也是比較昂貴的,有時候需要同時處理的事情比較多,就需要我們頻繁的進行線程的創建和銷毀,這樣花費的時間也是比較多的。為了解決這一問題,我們就可以引用線程池的概念。
所謂線程池就是將線程集中管理起來,當需要線程的時候,可以從線程池中獲取空閑的線程,這樣可以減少線程的頻繁創建與銷毀,節省很大的時間和減少很多不必要的操作。
在java中提供了ThreadPoolExecutor類來進行線程的管理,這個類繼承於AbstractExecutorService,而AbstractExecutorService實現了ExecutorService介面,我們可以使用ThreadPoolExecutor來進行線程池的創建。
在ThreadPoolExecutor的構造方法中,有多個參數,可以配置不同的參數來進行優化。這個類的源碼構造方法為:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)其中每個參數代表的意義分別為
corePoolSize : 線程池中的核心線程數量,當線程池中當前的線程數小於這個配置的時候,如果有一個新的任務到來,即使線程池中還存在空閑狀態的線程,程序也會繼續創建一個新的線程放進線程池當中
maximumPoolSize: 線程池中的線程最大數量
keepAliveTime:當線程池中的線程數量大於配置的核心線程數量(corePoolSize)的時候,如果當前有空閑的線程,則當這個空閑線程可以存在的時間,如果在keepAliveTime這個時間點內沒有新的任務使用這個線程,那麼這個線程將會結束,核心線程不會結束,但是如果配置了allowCoreThreadTimeOut = true,則當空閑時間超過keepAliveTime之後,線程也會被結束調,默認allowCoreThreadTimeOut = false,即表示默認情況下,核心線程會一直存在於線程池當中。
unit : 空閑線程保持連接時間(keepAliveTime)的時間單位
workQueue:阻塞的任務隊列,用來保存等待需要執行的任務。
threadFactory :線程工廠,可以根據自己的需求去創建線程的對象,設置線程的名稱,優先順序等屬性信息。
handler:當線程池中存在的線程數超過設置的最大值之後,新的任務就會被拒絕,可以自己定義一個拒絕的策略,當新任務被拒絕之後,就會使用hander方法進行處理。
在java中也提供了Executors工具類,在這個工具類中提供了多個創建線程池的靜態方法,其中包含newCachedThreadPool、newFixedThreadPool、newScheledThreadPool、newSingleThreadExecutor等。但是他們每個方法都是創建了ThreadPoolExecutor對象,不同的是,每個對象的初始 參數值不一樣;
③ 【Java基礎】線程池的原理是什麼
什麼是線程池?
總歸為:池化技術 ---》資料庫連接池 緩存架構 緩存池 線程池 內存池,連接池,這種思想演變成緩存架構技術---> JDK設計思想有千絲萬縷的聯系
首先我們從最核心的ThreadPoolExecutor類中的方法講起,然後再講述它的實現原理,接著給出了它的使用示例,最後討論了一下如何合理配置線程池的大小。
Java 中的 ThreadPoolExecutor 類
java.uitl.concurrent.ThreadPoolExecutor 類是線程池中最核心的一個類,因此如果要透徹地了解Java 中的線程池,必須先了解這個類。下面我們來看一下 ThreadPoolExecutor 類的具體實現源碼。
在 ThreadPoolExecutor 類中提供了四個構造方法:
④ Java線程池
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
⑤ java如何監控線程是否在運行
判斷是否在運行用isAlive方法哈。。
給你寫了個例子。。不知是不是你想要的。。
public class Thread100 {
/**
* @param args
*/
public static ThreadA ta = new ThreadA();
public static ThreadB tb = new ThreadB();
public static void main(String[] args) {
ta.start();
tb.start();
}
}
class ThreadA extends Thread {
@Override
public void run() {
int i = 0;
while(i < 100) {
if(Thread100.tb.isAlive()) {
System.out.println("B is alive");
}
System.out.println(i);
i++;
}
}
}
class ThreadB extends Thread {
@Override
public void run() {
int i = 0;
while(i < 100) {
if(Thread100.ta.isAlive()) {
System.out.println("A is alive");
}
System.out.println(i);
i++;
}
}
}