本文轉至:https://www.cnblogs.com/cnmenglang/p/6273761.html , 孟凡柱的專欄 的博客,在此謝謝博主!
1.new Thread的弊端
執行一個異步任務你還只是如下new Thread嗎
new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start();
說說弊端:
a. 每次new Thread新建對象性能差。
b. 線程缺乏統一管理,可能無限制新建線程,相互之間競爭,及可能占用過多系統資源導致死機或oom。
c. 缺乏更多功能,如定時執行、定期執行、線程中斷。
相比new Thread,Java提供的四種線程池的好處在於:
a. 重用存在的線程,減少對象創建、消亡的開銷,性能佳。
b. 可有效控制最大並發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
c. 提供定時執行、定期執行、單線程、並發數控制等功能。
2.Executors提供四種線程池
newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。線程池的規模不存在限制。
newFixedThreadPool 創建一個固定長度線程池,可控制線程最大並發數,超出的線程會在隊列中等待。
newScheduledThreadPool 創建一個固定長度線程池,支持定時及周期性任務執行。
newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
下面代碼說明:
(1). newCachedThreadPool
創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。示例代碼如下:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(index * 1000); } catch (InterruptedException e) { e.printStackTrace(); } cachedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(index); } }); }
線程池為無限大,當執行第二個任務時第一個任務已經完成,會復用執行第一個任務的線程,而不用每次新建線程。
(2). newFixedThreadPool
創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。示例代碼如下:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int index = i; fixedThreadPool.execute(new Runnable() { @Override public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); }
因為線程池大小為3,每個任務輸出index后sleep 2秒,所以每兩秒打印3個數字。
定長線程池的大小最好根據系統資源進行設置。
(3) newScheduledThreadPool
創建一個定長線程池,支持定時及周期性任務執行。延遲執行示例代碼如下:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS);
表示延遲3秒執行。
定期執行示例代碼如下:
scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("delay 1 seconds, and excute every 3 seconds"); } }, 1, 3, TimeUnit.SECONDS);
表示延遲1秒后每3秒執行一次。
ScheduledExecutorService比Timer更安全,功能更強大。
(4)、newSingleThreadExecutor
創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。示例代碼如下:
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; singleThreadExecutor.execute(new Runnable() { @Override public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); }
結果依次輸出,相當於順序執行各個任務。
2.ExecutorService中submit和execute的區別
以下這是submit 的源碼:
public abstract class AbstractExecutorService implements ExecutorService { protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); } protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); } public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; } public <T> Future<T> submit(Runnable task, T result) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task, result); execute(ftask); return ftask; } public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; } //.... }
可以看出submit最終返回的是FutureTask對象,而execute:
public interface Executor { void execute(Runnable command); }
具體的實現在ThreadPoolExecutor類中
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command); }
所以,submit內部調用execute,且submit有返回值,方便exception處理。
submit Demo:
import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Main { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); List<Future<String>> resultList = new ArrayList<Future<String>>(); // 創建10個任務並執行 for (int i = 0; i < 10; i++) { // 使用ExecutorService執行Callable類型的任務,並將結果保存在future變量中 Future<String> future = executorService.submit(new TaskWithResult(i)); // 將任務執行結果存儲到List中 resultList.add(future); } executorService.shutdown(); // 遍歷任務的結果 for (Future<String> fs : resultList) { try { System.out.println(fs.get()); // 打印各個線程(任務)執行的結果 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { executorService.shutdownNow(); e.printStackTrace(); return; } } } } class TaskWithResult implements Callable<String> { private int id; public TaskWithResult(int id) { this.id = id; } /** * 任務的具體過程,一旦任務傳給ExecutorService的submit方法,則該方法自動在一個線程上執行。 * * @return * @throws Exception */ public String call() throws Exception { System.out.println("call()方法被自動調用,干活!!! " + Thread.currentThread().getName()); if (new Random().nextBoolean()) throw new TaskException("Meet error in task." + Thread.currentThread().getName()); // 一個模擬耗時的操作 for (int i =9; i > 0; i--) ; return "call()方法被自動調用,任務的結果是:" + id + " " + Thread.currentThread().getName(); } } class TaskException extends Exception { public TaskException(String message) { super(message); } }
Runnable和Callable的區別是,
(1)Callable規定的方法是call(),Runnable規定的方法是run().
(2)Callable的任務執行后可返回值,而Runnable的任務是不能返回值得
(3)call方法可以拋出異常,run方法不可以
(4)運行Callable任務可以拿到一個Future對象,表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future對象可以了解任務執行情況,可取消任務的執行,還可獲取執行結果。