在Java中,我們執行非同步任務的代碼可以這麼寫。
ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<String> stringFuture = executorService.submit(() -> { System.out.println("你好,世界"); return "helloworld"; }); System.out.println(stringFuture.getClass().getName()); System.out.println(stringFuture.get());
在submit方法中傳入一個callable介面對象。裡面承載的就是非同步執行的Java代碼。 我們可以看到非同步執行的任務很簡單,列印一行話 你好,世界。然後將helloworld字串返回給Future<T>介面對象接受執行的結果。當我們執行 stringFuture.get()方法的時候,如果非同步任務還沒有執行完。那麼future.get()方法所在的線程是會阻塞的。
像我們平常自己起一個線程去執行,執行的結果一般是那不會來的。但是Callable介面和Future介面這兩個介面卻可以做到將線程執行完的計算結果給拿到。
所以帶著這樣一個問題我們去查看下jdk的源碼是怎樣實現的。
首先第一行代碼
ExecutorService executorService = Executors.newSingleThreadExecutor();
我們可以知道,建立了一個線程池。具體的代碼是這樣的。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));}
Executors類建立了一個ExecutorService介面的實作類別。
該類的繼承結構是這樣的。
其中建立的ExecutorService介面的實作類別主要使用的是DelegatedExecutorService這個類。該類中封裝又封裝了一個ExecutorService介面的實作類別。
static class DelegatedExecutorService extends AbstractExecutorService { private final ExecutorService e; DelegatedExecutorService(ExecutorService executor) { e = executor; } public void execute(Runnable command) { e.execute(command); } public void shutdown() { e.shutdown(); } public List<Runnable> shutdownNow() { return e.shutdownNow(); } public boolean isShutdown() { return e.isShutdown(); } public boolean isTerminated() { return e.isTerminated(); } public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return e.awaitTermination(timeout, unit); } public Future<?> submit(Runnable task) { return e.submit(task); } public <T> Future<T> submit(Callable<T> task) { return e.submit(task); } public <T> Future<T> submit(Runnable task, T result) { return e.submit(task, result); } public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { return e.invokeAll(tasks); } public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { return e.invokeAll(tasks, timeout, unit); } public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { return e.invokeAny(tasks); } public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return e.invokeAny(tasks, timeout, unit); }}
我們可以看到,該類的所有的方法實現全都是調用可內部封裝的ExecutorService介面的實作類別。
有讀者可能會問了,這個被封裝的介面的類是哪個類。這裡應該是ThreadPoolExecutor這個類。
我們可以看下整合關係圖
ThraedPoolExecutor類也是繼承了AbstractExecutorService這個類。這就好分析了。
接下來我們分析下面的代碼。
以後筆者直接將分析的內容以註解的形式寫在代碼旁邊
Future<String> stringFuture = executorService.submit(() -> { System.out.println("你好,世界"); return "helloworld";});
public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException();
//實際上這裡是new了一個FutureTask類的對象。
//FutureTask類實現了Runnable,Future<T>和RunnableFuture<V>三個介面,說明之後返回的FutureTask類對象可以
//當做Future<T>介面的實作類別來用 RunnableFuture<T> ftask = newTaskFor(task);
//Callable<T>介面裡的非同步代碼是在這行代碼被調用的。
//execute方法接收了剛才那個FutureTask類的對象做為參數去執行。我們到這個execute()方法裡去看看 execute(ftask); return ftask;}
我們可以看到該方法實現在ThreadPoolExecutor類裡面。當然execute(Runnable r)這個方法是聲明在Executor介面裡面的。
好,我們到execute()方法的實現裡面去分析分析
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); /* * Proceed in 3 steps: * * 1. If fewer than corePoolSize threads are running, try to * start a new thread with the given command as its first * task. The call to addWorker atomically checks runState and * workerCount, and so prevents false alarms that would add * threads when it shouldn't, by returning false. * * 2. If a task can be successfully queued, then we still need * to double-check whether we should have added a thread * (because existing ones died since last checking) or that * the pool shut down since entry into this method. So we * recheck state and if necessary roll back the enqueuing if * stopped, or start a new thread if there are none. * * 3. If we cannot queue task, then we try to add a new * thread. If it fails, we know we are shut down or saturated * and so reject the task. */ 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);}
//這個方法的形參就是剛才new出來的FutureTask類的對象。因為其也實現了Runnable介面,所以可以這樣傳遞
private boolean addWorker(Runnable firstTask, boolean core) { retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); // Check if queue empty only if necessary. if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false; for (;;) { int wc = workerCountOf(c); if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false; if (compareAndIncrementWorkerCount(c)) break retry; c = ctl.get(); // Re-read ctl if (runStateOf(c) != rs) continue retry; // else CAS failed due to workerCount change; retry inner loop } } boolean workerStarted = false; boolean workerAdded = false; Worker w = null; try { w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // Recheck while holding lock. // Back out on ThreadFactory failure or if // shut down before lock acquired. int rs = runStateOf(ctl.get()); if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } if (workerAdded) {
//這行代碼啟動了Callable介面裡的線程代碼。
//既然線程被啟動了,裡面我們就要去看看Runnable介面定義的run方法是如何?的,我們進入到FutureTask類的Run方法實作類別中去 t.start(); workerStarted = true; } } } finally { if (! workerStarted) addWorkerFailed(w); } return workerStarted;}
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try {
//這行代碼調用了Callable介面實作類別的call方法。得到的傳回值會返回給一個result變數
//下面的代碼將這個變數設定到FutureTask對象的成員變數outcome上。 result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran)
//就是這行代碼將Callable介面的call方法的執行結果設定到FutureTask類對象的outcome成員變數上
//我們可以點進入看一下是如何?的 set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); }}
protected void set(V v) { if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
//將Callable介面的call方法的計算結果放置到outcome變數上。 outcome = v; UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state finishCompletion(); }}
到這裡我們可以知道,執行完的結果是儲存在FutureTask類對象的outcome成員變數上的。
我們再去看下Future<T>介面定義的get方法
/** * @throws CancellationException {@inheritDoc} */public V get() throws InterruptedException, ExecutionException { int s = state; if (s <= COMPLETING) s = awaitDone(false, 0L);
//發現這裡有個report方法,點進去看一下 return report(s);}
@SuppressWarnings("unchecked")private V report(int s) throws ExecutionException {
//我們可以發現果然拿的是outcome成員變數的值 Object x = outcome; if (s == NORMAL) return (V)x; if (s >= CANCELLED) throw new CancellationException(); throw new ExecutionException((Throwable)x);}
到此文章的結束了