Java Executor框架

Executor 類結構

在這裏插入圖片描述
Executor提供了一種提交任務與任務具體如何執行的解耦方式。
ExecutorService 提供了shutdown,shutdownNow,invokeAll,invokeAny等線程管理的方法。

Runnable,Callable

Execucor執行的任務需要實現Runnable 或者 Callable
Runnable是沒有返回結果的,線程執行的方法是run方法,run方法不會拋出異常。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Callable可返回結果,線程執行的方法是call方法,call方法可拋出異常

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

當線程池submit Callable的時候,會把Callable封裝FutureTask,線程池執行的是FutureTask這個對象,同事返回這個FutureTask,FutureTask也實現了future,future示異步執行結果。我們可以通過get獲取任務結果,cancel取消任務執行。

public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

Future

future表示異步執行結果,通過future可以獲取任務的結果,可以取消任務的執行。

public interface Future<V> {
	//取消任務的執行
    boolean cancel(boolean mayInterruptIfRunning);
    //是否已經取消
    boolean isCancelled();
    //任務是否已經完成
    boolean isDone();
    //獲取任務的執行結果,會等待任務執行完
    V get() throws InterruptedException, ExecutionException;
    //獲取任務的執行結果,超時會拋出異常。
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

可以看看Future的實現類FutureTask
futureTask的run方法執行後會調用set(result), set方法會調用的一個方法finishCompletion表示完成了執行,finishCompletion會LockSupport.unpark(t) 解除線程阻塞,讓等待獲取結果的線程繼續執行。get的時候調用awaitDone阻塞當前線程。

 	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 {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {       
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
    
 	protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }
    
     private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
        done();
        callable = null;        // to reduce footprint
    }
    
 public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
        	//如果任務沒執行完,會阻塞當前線程等待獲取任務執行結果。
            s = awaitDone(false, 0L);
        return report(s);
    }
    

Executors工具類

創建固定數量的線程池,使用了無界隊列,這些數量的線程會一直存在直到調用了shutdown()。
使用了無界隊列,沒有調用shutdown的話不會拒絕任務,任務量很大的時候可能導致內存溢出。

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

創建一條線程的固定線程池,採用無界隊列。
使用了無界隊列,任務量很大的時候可能導致內存溢出。

 public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

創建緩存的線程池,根據需要創建線程,優先重用以前的線程,60秒內未使用的線程將終止並從緩存中移除。
緩存線程池使用的是傳遞隊列SynchronousQueue,這是一個沒有容器的隊列,類似於手遞手傳遞而不是先放在一個容器裏面,當生產者線程put元素的時候,如果沒有消費者take,那麼生產者線程就會阻塞。
允許創建的線程數量爲 Integer.MAX_VALUE ,可能會創建大量線程,從而導致內存溢出。

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

ThreadPoolExecutor

這是Java裏面經常有用到的自定義線程池。我的另外一篇博文裏面有詳細介紹。
[https://blog.csdn.net/liushengbaoblog/article/details/104899115]

ScheduledThreadPoolExecutor

給初始化延遲後執行任務或者定期執行任務的線程池。
隊列使用的是DelayedWorkQueue是一個實現了優先級的延遲隊列。DelayedWorkQueue中的任務會進行排序,執行所需時間短的放在前面先被執行。

建議使用ScheduledThreadPoolExecutor 而不是Timer
Timer 中的TimeTask 可能導致線程掛掉,後面的任務將不會執行。ScheduledThreadPoolExecutor 可以捕獲異常,並且還能通過重寫afterExecute對異常任務做處理。
Timer 是一個線程,如果任務耗時可能會延遲後面的任務。而ScheduledThreadPoolExecutor 可配置多個線程。

  public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章