爲何須要執行框架呢?
使用通常的new方法來建立線程有什麼問題呢?通常的new線程的方式通常要給出一個實現了Runnable接口的執行類,在其中重寫run()方法,而後再在將這個執行類的對象傳給線程以完成初始化,這個過程當中線程的定義和執行過程實際上是雜糅在一塊兒了,並且每次new一個新的線程出來在資源上頗有可能會產生沒必要要的消耗,所以咱們經過多線程執行框架來解決這兩個問題,其一能夠分離線程的定義和執行過程,其二能夠經過線程池來動態地管理線程以減少沒必要要的資源開銷。多線程
線程執行框架啓動線程
將要多線程執行的任務封裝爲一個Runnable對象,將其傳給一個執行框架Executor對象, Executor從線程池中選擇線程執行工做任務。框架
建立多線程框架對象調用線程執行任務
咱們一般經過Executors類的一些靜態方法來實例化Executor或ThreadPoolExecutor對象:ide
好比Executor對象來執行:函數
public class ThreadTest { public static void main(String[] args) { Executor executor = Executors.newSingleThreadExecutor(); executor.execute(new MyRunnable()); } } class MyRunnable implements Runnable { @Override public void run() { System.out.println("running"); } }
好比線程池的Executor對象來執行:this
public class ThreadTest { public static void main(String[] args) { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors .newFixedThreadPool(3); executor.execute(new MyRunnable()); } } class MyRunnable implements Runnable { @Override public void run() { System.out.println("running"); } }
Executors. newSingleThreadExecutor():一 個線程死掉後,自動從新建立後一個新的線程,因此沒有線程池的概念,不能被ThreadPoolExecutor接收;線程
Executors. newFixedThreadPool():固定數目的線程池;code
Executors. newCachedThreadPool():動態地增長和減小線程數;對象
多線程框架對象調用線程執行任務取回結果
實現了Runnable接口的執行類雖然能夠在run()方法裏寫入執行體,可是沒法返回結果值,由於run()方法是void型的,而Callable接口解決了這個問題,在繼承了Callable接口的執行類中重寫call()方法能夠設置返回值,當Executor對象使用submit()函數提交執行類的時候會由線程池裏的線程來運行,運行獲得的返回值能夠使用Future<V>接口來接,取得的返回值類型由V決定,Future<V>接口表示可能會獲得的返回值,可是有可能報異常,所以要拋出這些異常,而後能夠取得這些返回值。繼承
public class ThreadTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors .newCachedThreadPool(); MyCallable myCallable = new MyCallable(2); Future<Integer> result = executor.submit(myCallable); System.out.println(result.get()); } } class MyCallable implements Callable<Integer> { private int num; public MyCallable(int num) { this.num = num; } @Override public Integer call() throws Exception { return num * 2; } }
多線程框架對象調用線程執行任務完成第一個仍是所有完成就取回結果
使用submit()函數取回的結果不能控制任務是完成第一個仍是所有完成就取回結果,然而使用invokeAny()和invokeAll()函數便可得到這樣的效果,將執行體對象放入集合中傳入這兩個函數,前者能夠在完成任務的多線程有一個(第一個)完成時就返回結果,所以結果類型是單結果,然後者則須要等待全部執行任務的線程都執行完畢才返回結果,所以結果還是集合。接口
1.invokeAny():
public class ThreadTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5); List<MyCallable> callables = new ArrayList<>(); for(int i=0;i<10;i++){ MyCallable myCallable = new MyCallable(i); callables.add(myCallable); } Integer res = executor.invokeAny(callables); System.out.println(res); } } class MyCallable implements Callable<Integer> { private int num; public MyCallable(int num) { this.num = num; } @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName() + " is running"); return num * 2; } }
2.invokeAll():
public class ThreadTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors .newFixedThreadPool(5); List<MyCallable> callables = new ArrayList<MyCallable>(); for (int i = 0; i < 10; i++) { MyCallable myCallable = new MyCallable(i); callables.add(myCallable); } List<Future<Integer>> res = executor.invokeAll(callables); for (Future<Integer> future : res) { System.out.println(future.get()); } } } class MyCallable implements Callable<Integer> { private int num; public MyCallable(int num) { this.num = num; } @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName() + " is running"); return num * 2; } }
多線程框架對象執行定時任務
使用Executor的schedule()函數族來調度線程池中的線程來執行callable執行類對象中的call()定時任務:
public class ThreadTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ScheduledExecutorService executorService = Executors .newScheduledThreadPool(2); MyCallable callable = new MyCallable(2); executorService.schedule(callable, 10, TimeUnit.SECONDS); executorService.shutdown(); } } class MyCallable implements Callable<Integer> { private int num; public MyCallable(int num) { this.num = num; } @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName() + " is running"); return num * 2; } }