天天看點

Java線程池ThreadPool相關知識

轉載:https://blog.csdn.net/shakespeare001/article/details/51330745

在java.util.concurrent包下,提供了一系列與線程池相關的類,

合理的使用線程池,可以帶來多個好處:

(1)降低資源消耗。通過重複利用已建立的線程降低線程建立和銷毀造成的消耗;

(2)提高響應速度。當任務到達時,任務可以不需要等到線程建立就能立即執行;

(3)提高線程的可管理性。線程是稀缺資源,如果無限制的建立,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的配置設定,調優和監控。

線程池可以應對突然大爆發量的通路,通過有限個固定線程為大量的操作服務,減少建立和銷毀線程所需的時間。

我們一般通過工具類Executors的靜态方法(如newFixedThreadPool())來擷取ThreadPoolExecutor線程池或靜态方法(如newScheduledThreadPool())來擷取ScheduleThreadPoolExecutor線程池。如下使用:

ExecutorService threadpool= Executors.newFixedThreadPool(10);

我們指定了擷取10個數量的固定線程池。

當送出一個任務到線程池時,線程池會建立一個線程來執行任務,即使其他空閑的基本線程能夠執行新任務也會建立線程,等到需要執行的任務數大于線程池基本大小時就不再建立。如果調用了線程池的prestartAllCoreThreads方法,線程池會提前建立并啟動所有基本線程。

送出任務的兩種方式:

(1)通過execute()方法,如:

ExecutorService threadpool= Executors.newFixedThreadPool(10);
threadpool.execute(new Runnable(){...});
           

(2)通過submit()方法,如:

Future<?> future = threadpool.submit(new Runnable(){...});
    try {
            Object res = future.get();
        } catch (InterruptedException e) {
            // 進行中斷異常
            e.printStackTrace();
        } catch (ExecutionException e) {
            // 處理無法執行任務異常
            e.printStackTrace();
        }finally{
            // 關閉線程池
            executor.shutdown();
        }
           

使用submit 方法來送出任務,它會傳回一個Future對象,通過future的get方法來擷取傳回值,get方法會阻塞住直到任務完成,而使用get(long timeout, TimeUnit unit)方法則會阻塞一段時間後立即傳回,這時有可能任務沒有執行完。

Java線程池ThreadPool相關知識

從上圖我們可以看出,當送出一個新任務到線程池時,線程池的處理流程如下:

1、首先線程池判斷基本線程池是否已滿(< corePoolSize ?)?沒滿,建立一個工作線程來執行任務。滿了,則進入下個流程。

2、其次線程池判斷工作隊列是否已滿?沒滿,則将新送出的任務存儲在工作隊列裡。滿了,則進入下個流程。

3、最後線程池判斷整個線程池是否已滿(< maximumPoolSize ?)?沒滿,則建立一個新的工作線程來執行任務,滿了,則交給飽和政策來處理這個任務。

也就是說,線程池優先要建立出基本線程池大小(corePoolSize)的線程數量,沒有達到這個數量時,每次送出新任務都會直接建立一個新線程,當達到了基本線程數量後,又有新任務到達,優先放入等待隊列,如果隊列滿了,才去建立新的線程(不能超過線程池的最大數maxmumPoolSize)。

繼續閱讀