Java Executor 框架學習總結
大多數併發都是通過任務執行的方式來實現的。一般有兩種方式執行任務:序列和並行。
class SingleThreadWebServer { public static void main(String[] args) throws Exception { ServerSocket socket = new ServerSocket(80); while(true) { Socket conn = socket.accept(); handleRequest(conn); } } } class ThreadPerTaskWebServer { public static void main(String[] args) throws Exception { ServerSocket socket = new ServerSocket(80); while(true) { final Socket conn = socket.accept(); Runnable task = new Runnable() { public void run() { handleRequest(conn); } }; new Thread(task).start(); } } }
當然上面的這兩種方式都是有問題的。單執行緒的問題就是併發量會是瓶頸,多執行緒版本就是無限制的建立執行緒會導致資源不足問題。
Executor 框架
任務是一組邏輯工作單元,而執行緒是使任務非同步執行的機制。
JDK 提供了 Executor 介面:
public interface Executor { void execute(Runnable command); }
雖然 Executor 介面比較簡單,但是卻是非同步任務執行框架的基礎,該框架能支援多種不同型別的任務執行策略。它提供了一種標準的方式把任務的提交過程與執行過程進行了解耦。用 Runnable 來代表任務。Executor 的實現提供了對生命週期的支援以及統計資訊應用程式管理等機制。
Executor 是基於生產者消費者模式的,提交任務的操作相當於生產者,執行任務的執行緒相當於消費。
基於 Executor 的 WebServer 例子如下:
public class TaskExecutorWebServer { private static final int NTHREADS = 100; private static final Executor exec = Executors.newFixedThreadPool(NTHREADS); public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(80); while (true) { final Socket conn = serverSocket.accept(); Runnable task = new Runnable() { @Override public void run() { handleRequest(conn); } }; exec.execute(task); } } }
另外可以自己實現 Executor 來控制是併發還是並行的,如下面程式碼:
/** * 執行已提交的 Runnable 任務的物件。 * 此介面提供一種將任務提交與每個任務將如何執行的機制(包括執行緒使用的細節、排程等)分離開來的方法。 * 通常使用 Executor 而不是顯式地建立執行緒。 * * * @author renchunxiao * */ public class ExecutorDemo { public static void main(String[] args) { Executor executor = new ThreadExecutor(); executor.execute(new Runnable() { @Override public void run() { // do something } }); Executor executor2 = new SerialExecutor(); executor2.execute(new Runnable() { @Override public void run() { // do something } }); } } /** * 建立一個執行緒來執行 command * * @author renchunxiao * */ class ThreadExecutor implements Executor { @Override public void execute(Runnable command) { new Thread(command).start(); } } /** * 序列執行 command * * @author renchunxiao * */ class SerialExecutor implements Executor { @Override public void execute(Runnable command) { command.run(); } }
執行緒池
執行緒池就是執行緒的資源池,可以通過 Executors 中的靜態工廠方法來建立執行緒池。
- newFixedThreadPool。建立固定長度的執行緒池,每次提交任務建立一個執行緒,直到達到執行緒池的最大數量,執行緒池的大小不再變化。
- newSingleThreadExecutor。單個執行緒池。
- newCachedThreadPool。根據任務規模變動的執行緒池。
- newScheduledThreadPool。建立固定長度的執行緒池,以延遲或定時的方式來執行任務。
JVM 只有在所有非守護執行緒全部終止後才會退出,所以,如果無法正確的關閉 Executor,那麼 JVM 就無法結束。
為了解決執行服務的生命週期問題,有個擴充套件 Executor 介面的新介面 ExecutorService。
public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException; <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
ExecutorService 生命週期有三種狀態:執行、關閉、已終止。ExecutorService 在初始建立時處於執行狀態。shutdown 方法會平緩關閉:不在接受新的任務,並且等待已經執行的任務執行完成(包括那些還未開始的任務)。shutdownNow 方法將粗暴關閉:它將嘗試取消所有執行中的任務,並且不再啟動佇列中尚未開始的任務。所有任務都執行完成後進入到已終止狀態。
Callable 和 Future
Executor 框架使用 Runnable 作為基本的任務表示形式。Runnable 是一種有侷限性的抽象,它的 run 方法不能返回值和丟擲一個受檢查異常。
許多工實際上是存在延時的計算,例如資料庫查詢,從網路獲取資源。對於這些任務,Callable 是更好的抽象,它認為 call 將返回一個值,並且可能丟擲異常。
Executor 執行的任務有四個生命週期階段:建立、提交、開始和完成。由於有些任務需要很長時間有可能希望取消,在 Executor 框架當中,已提交未開始的任務可以取消。
Future 表示一個任務的生命週期,並且提供了相應的方法來判斷是否已經完成或取消,以及獲取任務的結果和取消任務等。
相關文章
- Dubbo框架學習總結框架
- rose框架學習總結ROS框架
- Java學習總結Java
- Java多執行緒學習(八)執行緒池與Executor 框架Java執行緒框架
- GoWeb框架Gin學習總結GoWeb框架
- 奈學:Executor框架的概述框架
- Java集合學習總結Java
- Java學習之LinkedHashMap學習總結JavaHashMap
- Java集合類學習總結Java
- 【java學習之容器總結】Java
- Java 併發程式設計 Executor 框架Java程式設計框架
- 【java學習】java知識點總結Java
- Java中IO流學習總結Java
- 學習Java第六週總結Java
- GoWeb框架Gin學習總結proto檔案GoWeb框架
- Java 執行緒 Executor 框架詳解與使用Java執行緒框架
- Java記憶體模型學習總結Java記憶體模型
- java學習總結及心得體會Java
- 學習Java的第五週總結Java
- Java資料結構之Map學習總結Java資料結構
- Java資料結構之Set學習總結Java資料結構
- JAVA基礎學習-數字與字串學習總結Java字串
- Java初階段學習的複習總結Java
- 【初識】-JUC·Executor框架框架
- Java集合框架學習Java框架
- 學習總結
- 《java併發程式設計的藝術》Executor框架Java程式設計框架
- Java-Stream流方法學習及總結Java
- Java 併發程式設計學習總結Java程式設計
- Java高階特性之反射學習總結Java反射
- Java高階特性之列舉學習總結Java
- java 學習之路 --工作後兩年總結Java
- Java 8 Lambda 表示式學習心得總結Java
- java集合框架基礎總結Java框架
- Java集合框架使用總結薦Java框架
- java spring 框架學習JavaSpring框架
- Java專案中MongoDb學習和使用總結JavaMongoDB
- JAVA學習-------第二週知識點總結Java