Java線程池(Callable+Future模式)
Java通過Executors提供四種線程池
1)newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
2)newFixedThreadPool 創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。
3)newScheduledThreadPool 創建一個定長線程池,支持定時及周期性任務執行。
4)newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
在多線程的開發中往往會遇到這種情況:主線程需要知道子線程的運行結果,以便確定如何執行任務.JDK1.5以后就提供了Callable和Future,通過它們可以在任務執行完畢之后得到任務執行結果。
步驟:
1)任務類實現Callable接口
2)創建線程池:ExecutorService es = Executors.newCachedThreadPool();
3)執行任務:chuju cj = new chuju();Future<Boolean> future = es.submit(cj);
4)獲取子線程中任務的執行結果:future.get()
下面通過實例簡單說下其用法:
場景:假如你想做飯,但是沒有廚具,也沒有食材。網上購買廚具比較方便,食材去超市買更放心,即買出具、買食材,這兩個任務異步執行,買好后才能去做飯。
1)chuju
public class chuju implements Callable<Boolean>{ @Override public Boolean call() throws Exception { try{ System.out.println("買廚具"); Thread.sleep(3000); System.out.println("買好廚具"); }catch (InterruptedException e){ e.printStackTrace(); } return true; } }
2)shicai
public class shicai implements Callable<Boolean>{ @Override public Boolean call() throws Exception { try{ System.out.println("買食材"); Thread.sleep(1000); System.out.println("買好食材"); }catch(InterruptedException e){ e.printStackTrace(); } return true; } }
3)zuofan
public class zuofan implements Callable<Boolean>{ @Override public Boolean call() throws Exception { try{ System.out.println("做飯"); Thread.sleep(5000); System.out.println("做好飯"); }catch (InterruptedException e){ e.printStackTrace(); } return true; } }
4)Main
public class Main { public static void main(String[] args) { ExecutorService es = Executors.newCachedThreadPool(); chuju cj = new chuju(); shicai sc = new shicai(); Future<Boolean> f1 = es.submit(cj); Future<Boolean> f2 = es.submit(sc); try{ Boolean b1 = f1.get();//會阻塞當前線程 Boolean b2 = f2.get(); System.out.println(b1); System.out.println(b2); if(b1 && b2){ zuofan zf = new zuofan(); es.submit(zf); } }catch(InterruptedException e){ e.printStackTrace(); }catch (ExecutionException e){ e.printStackTrace(); } es.shutdown(); } }
5)執行結果
Connected to the target VM, address: '127.0.0.1:57304', transport: 'socket'
買廚具
買食材
買好食材
買好廚具
true
true
做飯
Disconnected from the target VM, address: '127.0.0.1:57304', transport: 'socket'
做好飯
Process finished with exit code 0
從運行結果可以看出,買出具代碼和買食材代碼是異步執行的,這兩個都執行完畢后,才執行的做飯代碼。那么為什么子線程zuofan沒有先執行呢?由於Future的get()方法沒有得到返回值,讓當前線程暫時掛起了。
注意:Future的get()方法,如果拿不到結果會阻塞當前線程。