所有的現代操作系統都通過進程和線程來支持并發。進程是通常彼此獨立運行的程序的實例,比如,如果你啟動了一個Java程序,操作系統產生一個新的進程,與其他程序一起并行執行。在這些進程的內部,我們使用線程并發執行代碼,因此,我們可以最大限度的利用CPU可用的核心(core)。Java從JDK1.0開始執行線程。在開始一個新的線程之前,你必須指定由這個線程執行的代碼,通常稱為task。這可以通過實現Runnable:
一個定義了一個無返回值無參數的run()
方法的函數接口,如下面的代碼所示:
Runnable task = () -> { //JDK 1.8中的Lambda 表達式 String threadName = Thread.currentThread().getName(); System.out.2. java 線程池的使用
上面繼承Thread類和實現Runnable接口,可以實現多線程。但是如果并發的線程數量很多,并且每個線程都是執行一個時間很短的任務就結束了,這樣頻繁創建線程就會大大降低系統的效率,因為頻繁創建線程和銷毀線程需要時間。那么有沒有一種辦法使得線程可以復用,就是執行完一個任務,并不被銷毀,而是可以繼續執行其他的任務?在Java中可以通過線程池來達到這樣的效果。今天我們就來詳細講解一下Java的線程池,首先我們從最核心的ThreadPoolExecutor類中的方法講起,然后再講述它的實現原理,接著給出了它的使用示例,最后討論了一下如何合理配置線程池的大小。
Java中的ThreadPoolExecutor類,java..uitl.concurrent.ThreadPoolExecutor類是線程池中最核心的一個類,因此如果要透徹地了解Java中的線程池,必須先了解這個類。下面我們來看一下ThreadPoolExecutor類的具體實現源碼。
public class ThreadPoolExecutor extends AbstractExecutorService { public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); }從上面的代碼可以得知,ThreadPoolExecutor繼承了AbstractExecutorService類,并提供了四個構造器,事實上,通過觀察每個構造器的源碼具體實現,發現前面三個構造器都是調用的第四個構造器進行的初始化工作。下面解釋下一下構造器中各個參數的含義:
coorPoolSize:核心池的大小,這個參數跟后面講述的線程池的實現原理有非常大的關系。在創建了線程池后,默認情況下,線程池中并沒有任何線程,而是等待有任務到來才創建線程去執行任務,除非調用了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個方法的名字就可以看出,是預創建線程的意思,即在沒有任務到來之前就創建corePoolSize個線程或者一個線程。默認情況下,在創建了線程池后,線程池中的線程數為0,當有任務來之后,就會創建一個線程去執行任務,當線程池中的線程數目達到corePoolSize后,就會把到達的任務放到緩存隊列當中;maximumPoolSize:線程池最大線程數,這個參數也是一個非常重要的參數,它表示在線程池中最多能創建多少個線程;keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止。默認情況下,只有當線程池中的線程數大于corePoolSize時,keepAliveTime才會起作用,直到線程池中的線程數不大于corePoolSize,即當線程池中的線程數大于corePoolSize時,如果一個線程空閑的時間達到keepAliveTime,則會終止,直到線程池中的線程數不超過corePoolSize。但是如果調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數不大于corePoolSize時,keepAliveTime參數也會起作用,直到線程池中的線程數為0;unit參數:keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態屬性:
TimeUnit.DAYS; //天TimeUnit.HOURS; //小時TimeUnit.MINUTES; //分鐘TimeUnit.SECONDS; //秒TimeUnit.MILLISECONDS; //毫秒TimeUnit.MICROSECONDS; //微妙TimeUnit.NANOSECONDS; //納秒workQueue:一個阻塞隊列,用來存儲等待執行的任務,這個參數的選擇也很重要,會對線程池的運行過程產生重大影響,一般來說,這里的阻塞隊列有以下幾種選擇:
新聞熱點
疑難解答