線程池,其實就是一個容納多個線程的容器,其中的線程可以反復使用,省去了頻繁創建線程對象的操作,
無需反復創建線程而消耗過多資源。
我們詳細的解釋一下為什么要使用線程池?
在java中,如果每個請求到達就創建一個新線程,開銷是相當大的。在實際使用中,創建和銷毀線程花費的時間和消耗的系統資源都相當大,
甚至可能要比在處理實際的用戶請求的時間和資源要多的多。除了創建和銷毀線程的開銷之外,活動的線程也需要消耗系統資源。
如果在一個jvm里創建太多的線程,可能會使系統由於過度消耗內存或“切換過度”而導致系統資源不足。為了防止資源不足,
需要采取一些辦法來限制任何給定時刻處理的請求數目,盡可能減少創建和銷毀線程的次數,特別是一些資源耗費比較大的線程的創建和銷毀,
盡量利用已有對象來進行服務。
線程池主要用來解決線程生命周期開銷問題和資源不足問題。通過對多個任務重復使用線程,線程創建的開銷就被分攤到了多個任務上了,
而且由於在請求到達時線程已經存在,所以消除了線程創建所帶來的延遲。這樣,就可以立即為請求服務,使用應用程序響應更快。另外,
通過適當的調整線程中的線程數目可以防止出現資源不足的情況。
2.1 使用線程池方式--Runnable接口
通常,線程池都是通過線程池工廠創建,再調用線程池中的方法獲取線程,再通過線程去執行任務方法。
l Executors:線程池創建工廠類
n public static ExecutorService newFixedThreadPool(int nThreads):返回線程池對象
l ExecutorService:線程池類
n Future<?> submit(Runnable task):獲取線程池中的某一個線程對象,並執行
l Future接口:用來記錄線程任務執行完畢后產生的結果。線程池創建與使用
l 使用線程池中線程對象的步驟:
n 創建線程池對象
n 創建Runnable接口子類對象
n 提交Runnable接口子類對象
n 關閉線程池
代碼演示: public class ThreadPoolDemo { public static void main(String[] args) { //創建線程池對象 ExecutorService service = Executors.newFixedThreadPool(2);//包含2個線程對象 //創建Runnable實例對象 MyRunnable r = new MyRunnable(); //自己創建線程對象的方式 //Thread t = new Thread(r); //t.start(); ---> 調用MyRunnable中的run() //從線程池中獲取線程對象,然后調用MyRunnable中的run() service.submit(r); //再獲取個線程對象,調用MyRunnable中的run() service.submit(r); service.submit(r); //注意:submit方法調用結束后,程序並不終止,是因為線程池控制了線程的關閉。將使用完的線程又歸還到了線程池中 //關閉線程池 //service.shutdown(); } } Runnable接口實現類 public class MyRunnable implements Runnable { @Override public void run() { System.out.println("我要一個教練"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("教練來了: " +Thread.currentThread().getName()); System.out.println("教我游泳,交完后,教練回到了游泳池"); } }
2.2 使用線程池方式—Callable接口
l Callable接口:
與Runnable接口功能相似,用來指定線程的任務。其中的call()方法,用來返回線程任務執行完畢后的結果,call方法可拋出異常。
l ExecutorService:線程池類
n <T> Future<T> submit(Callable<T> task):獲取線程池中的某一個線程對象,並執行線程中的call()方法
l Future接口:用來記錄線程任務執行完畢后產生的結果。線程池創建與使用
l 使用線程池中線程對象的步驟:
n 創建線程池對象
n 創建Callable接口子類對象
n 提交Callable接口子類對象
n 關閉線程池
代碼演示: public class ThreadPoolDemo { public static void main(String[] args) { //創建線程池對象 ExecutorService service = Executors.newFixedThreadPool(2);//包含2個線程對象 //創建Callable對象 MyCallable c = new MyCallable(); //從線程池中獲取線程對象,然后調用MyRunnable中的run() service.submit(c); //再獲取個教練 service.submit(c); service.submit(c); //注意:submit方法調用結束后,程序並不終止,是因為線程池控制了線程的關閉。將使用完的線程又歸還到了線程池中 //關閉線程池 //service.shutdown(); } } Callable接口實現類,call方法可拋出異常、返回線程任務執行完畢后的結果 public class MyCallable implements Callable { @Override public Object call() throws Exception { System.out.println("我要一個教練:call"); Thread.sleep(2000); System.out.println("教練來了: " +Thread.currentThread().getName()); System.out.println("教我游泳,交完后,教練回到了游泳池"); return null; } }