欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

線程池中execute與submit的區(qū)別說明

 更新時(shí)間:2022年03月23日 14:54:20   作者:每年進(jìn)步一點(diǎn)點(diǎn)  
這篇文章主要介紹了線程池execute與submit的區(qū)別說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

線程池execute與submit區(qū)別

在使用線程池的時(shí)候,看到execute()與submit()方法。都可以使用線程池執(zhí)行一個(gè)任務(wù),但是兩者有什么區(qū)別呢?

execute

void execute(Runnable command);

submit

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

相同點(diǎn):

1 都可以執(zhí)行任務(wù)

2 參數(shù)都支持runnable

不同點(diǎn):

1 submit支持接收返回值 詳見例1。

2 execute 任務(wù)里面的異常必須捕獲,不能向上拋出;submit支持的Callable支持向上拋出異常,需要由返回值.get()來進(jìn)行接收。詳見例2。

例1

public class ExecutorTest {?
? ? public static ExecutorService executorService = Executors.newFixedThreadPool(3);?
? ? public static void main(String[] args) {
? ? ? ? Future<?> result1 = executorService.submit(new Callable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public Object call() throws Exception {
? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(10);
? ? ? ? ? ? ? ? System.out.println("Thread1 sleep 10 seconds");
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? Future<?> result2 = executorService.submit(new Callable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public Object call() throws Exception {
? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(5);
? ? ? ? ? ? ? ? System.out.println("Thread2 sleep 5 seconds");
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? try {
? ? ? ? ? ? System.out.println("Thread1 return:"+result1.get());
? ? ? ? ? ? System.out.println("Thread2 return:"+result2.get());
? ? ? ? ? ? System.out.println("finished");
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } catch (ExecutionException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }?
? ? }
}

該例子的返回結(jié)果:

Thread2 sleep 5 seconds
Thread1 sleep 10 seconds
Thread1 return:true
Thread2 return:false
finished

解釋:可以看到接收到了兩個(gè)線程的返回結(jié)果。利用thread.sleep來模擬耗時(shí)操作,直到兩個(gè)線程執(zhí)行完畢之后,才會(huì)輸出finished。利用Callable的返回阻塞,來等待這n個(gè)線程的執(zhí)行完畢,然后將這n個(gè)線程的結(jié)果響應(yīng)回去;其執(zhí)行時(shí)間,基本上取決于最耗時(shí)的那個(gè)線程。

適用場景:在某些情況下,需要獲得一組線程的結(jié)果,給調(diào)用端。

例2

而execute不支持向上拋出異常,必須將異常捕獲。

線程池submit和execute方法原理

線程池的作用

1. 避免大量的線程強(qiáng)占資源

2. 避免大量的線程創(chuàng)建和銷毀帶來的開銷  

線程池的原理

創(chuàng)建線程池的時(shí)候,可以使用executors的靜態(tài)方法,也可以使用new ThreadPoolExecutor的方式手動(dòng)創(chuàng)建線程池,通過在線程池中指定參數(shù)達(dá)到創(chuàng)建不同類型的線程池的效果

其中,executors底層其實(shí)也是調(diào)用的new ThreadPoolExecutor()的方式創(chuàng)建的,是對不同線程池的封裝,

線程的執(zhí)行有兩種方式,一種是submit(runnable v)的形式,一種是execute(runnable b) 的形式,不同的是submit可以返回一個(gè)future的實(shí)現(xiàn)類,相同的一點(diǎn)是submit底層其實(shí)也是調(diào)用的execute

調(diào)用execut方法,首先判斷傳入的參數(shù)是否為空,如果為空,拋出異常,如果不為空,使用獲取ctl值,計(jì)算出當(dāng)前線程狀態(tài)碼,通過狀態(tài)碼計(jì)算出當(dāng)前線程池工作線程是否小于核心線程數(shù)量

如果小于,判斷添加工作線程操作是否正常,如果正常,直接返回,如果不正常,繼續(xù)執(zhí)行獲取ctl值,在添加工作線程的過程中,首先通過循環(huán)的方式保證ctl在加1的情況下狀態(tài)同步,如果不同步,一直循環(huán)到同步為止,添加完成后,創(chuàng)建線程工作對象,把工作線程添加到set集合中,并執(zhí)行.start,如果執(zhí)行不成功,從set中刪除添加的worker對象,并且ctl回滾到之前沒有自增的值.

如果上述中添加工作線程失敗,或者當(dāng)前線程池中工作線程數(shù)量操作和信息數(shù)量,執(zhí)行下列邏輯

判斷當(dāng)前線程池狀態(tài)是否是running狀態(tài):

如果不是running狀態(tài),或者是running狀態(tài),并且添加到線程隊(duì)列失敗,重新添加個(gè)工作線程,此時(shí)入?yún)⒅械诙€(gè)參數(shù)用于添加工作線程的邏輯中當(dāng)前工作線程數(shù)量與最大線程數(shù)量做對比,如果添加失敗,執(zhí)行reject處理類處理

如果是running狀態(tài),并且添加隊(duì)列成功,重新獲取ctl值,判斷當(dāng)前線程池狀態(tài)如果是不是running狀態(tài),并且從對象中刪除成功,則當(dāng)前線程交給拒絕線程處理器處理,如果不滿足上面條件,判斷當(dāng)前線程池的工作線程數(shù)如果為0,重新添加一個(gè)不帶任務(wù)的線程. 

//AbstractExecutorService.java文件
? ? // executorService 中的 submit 方法
? ? public Future<?> submit(Runnable task) {
? ? ? ? // 首先判斷傳入的runnable 對象是否為空
? ? ? ? if (task == null) throw new NullPointerException();
? ? ? ? // 創(chuàng)建一個(gè) futuretask 對象
? ? ? ? RunnableFuture<Void> ftask = newTaskFor(task, null);
? ? ? ? execute(ftask);
? ? ? ? return ftask;
? ? }
? ? // 根據(jù)runnable 創(chuàng)建一個(gè)futuretask對象
? ? protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
? ? ? ? return new FutureTask<T>(runnable, value);
? ? }
? ? // ThreadPoolExecutor.java文件
? ? // 執(zhí)行創(chuàng)建線程池的方法
? ? public void execute(Runnable command) {
? ? ? ? // 首先判斷傳入的線程是否為空
? ? ? ? if (command == null)
? ? ? ? ? ? // 為空,拋出異常
? ? ? ? ? ? throw new NullPointerException();
? ? ? ? // 獲取線程池的狀態(tài)碼, 這個(gè)狀態(tài)碼是自增的,原子類型的自增, 在執(zhí)行addworker后ctl會(huì)加1
? ? ? ? int c = ctl.get();
? ? ? ? // 通過狀態(tài)碼,獲取線程池中的線程的數(shù)量,如果小于核心數(shù)量
? ? ? ? if (workerCountOf(c) < corePoolSize) {
? ? ? ? ? ? // 添加線程到線程池,并且為true時(shí)使用核心線程數(shù)作為邊界,如果false ,使用最大數(shù)量線程數(shù)作為邊界
? ? ? ? ? ? if (addWorker(command, true))
? ? ? ? ? ? ? ? // 添加完成后,返回
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? // 如果添加失敗,重新獲取狀態(tài)值
? ? ? ? ? ? c = ctl.get();
? ? ? ? }
? ? ? ? // 執(zhí)行下面邏輯有兩種情況
? ? ? ? // ? ? ?1. 工作線程數(shù)大于核心線程
? ? ? ? // ? ? ?2. 添加線程時(shí)出錯(cuò)
? ? ? ? // 如果線程池中線程的數(shù)量大于核心的數(shù)量, 判斷如果是運(yùn)行狀態(tài), 并且也把線程加進(jìn)了阻塞隊(duì)列 workQueue 中
? ? ? ? if (isRunning(c) && workQueue.offer(command)) {
? ? ? ? ? ? // 重新獲取 線程池 狀態(tài)值
? ? ? ? ? ? int recheck = ctl.get();
? ? ? ? ? ? // 判斷當(dāng)前線程池如果不是運(yùn)行狀態(tài),并且成功從隊(duì)列中移除(從workQueue中移除線程, 并嘗試終止線程池)
? ? ? ? ? ? if (! isRunning(recheck) && remove(command))
? ? ? ? ? ? ? ? // 執(zhí)行拒絕執(zhí)行線程的處理
? ? ? ? ? ? ? ? reject(command);
? ? ? ? ? ? ? ? // 如果工作線程數(shù)為0
? ? ? ? ? ? else if (workerCountOf(recheck) == 0)
? ? ? ? ? ? ? ? // 添加一個(gè)null的工作包裝對象
? ? ? ? ? ? ? ? addWorker(null, false);
? ? ? ? } else if (!addWorker(command, false))
? ? ? ? ? ? // 如果添加到線程池中出錯(cuò),執(zhí)行拒接的線程
? ? ? ? ? ? reject(command);
? ? }
? ? // 創(chuàng)建一個(gè)原子類對象用于計(jì)算線程的中狀態(tài)
? ? private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
? ? // integer.size 為 32
? ? private static final int COUNT_BITS = Integer.SIZE - 3;
? ? private static final int CAPACITY ? = (1 << COUNT_BITS) - 1;
? ? // 即高3位為1,低29位為0,該狀態(tài)的線程池會(huì)接收新任務(wù),也會(huì)處理在阻塞隊(duì)列中等待處理的任務(wù)
? ? private static final int RUNNING ? ?= -1 << COUNT_BITS;
? ? // 即高3位為0,低29位為0,該狀態(tài)的線程池不會(huì)再接收新任務(wù),但還會(huì)處理已經(jīng)提交到阻塞隊(duì)列中等待處理的任務(wù)
? ? private static final int SHUTDOWN ? = ?0 << COUNT_BITS;
? ? // 即高3位為001,低29位為0,該狀態(tài)的線程池不會(huì)再接收新任務(wù),不會(huì)處理在阻塞隊(duì)列中等待的任務(wù),而且還會(huì)中斷正在運(yùn)行的任務(wù)
? ? private static final int STOP ? ? ? = ?1 << COUNT_BITS;
? ? // 即高3位為010,低29位為0,所有任務(wù)都被終止了,workerCount為0,為此狀態(tài)時(shí)還將調(diào)用terminated()方法
? ? private static final int TIDYING ? ?= ?2 << COUNT_BITS;
? ? // 即高3位為100,低29位為0,terminated()方法調(diào)用完成后變成此狀態(tài) ?
? ? private static final int TERMINATED = ?3 << COUNT_BITS;
? ? // 用戶計(jì)算線程的狀態(tài) 32位中 高3位為1 低29位為0?
? ? private static int runStateOf(int c) ? ? { return c & ~CAPACITY; }
? ? // 用于計(jì)算線程池中線程的數(shù)量 32位中 高3位為0 ?低29位為1
? ? private static int workerCountOf(int c) ?{ return c & CAPACITY; }
? ? // rs 為 runState, wc 為 workerCount 通過工作狀態(tài)和線程數(shù)量來計(jì)算出 ctl
? ? private static int ctlOf(int rs, int wc) { return rs | wc; }
? ? // 添加工作線程的方法
? ? private boolean addWorker(Runnable firstTask, boolean core) {
? ? ? ? // 設(shè)置循環(huán)跳出點(diǎn),如果執(zhí)行到某個(gè)位置,使用break,直接跳出的是這個(gè)標(biāo)簽范圍內(nèi)的所有循環(huán)
? ? ? ? retry:
? ? ? ? for (;;) {
? ? ? ? ? ? // 獲取線程狀態(tài)
? ? ? ? ? ? int c = ctl.get();
? ? ? ? ? ? int rs = runStateOf(c);
? ? ? ? ? ? // 判斷線程池狀態(tài)是否在shutdown上以及 狀態(tài)不是關(guān)閉并且添加的線程不為空,并且線程隊(duì)列中的線程不是空的
? ? ? ? ? ? if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
? ? ? ? ? ? ? ? // 如果滿足上面條件,說明線程池已經(jīng)不適合添加新的線程了, 直接返回false
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? // 如果不滿足上面條件,說明線程池可以添加線程, 下面這個(gè)循環(huán)主要是對ctl進(jìn)行操作,保證在增1后線程狀態(tài)保持同步
? ? ? ? ? ? for (;;) {
? ? ? ? ? ? ? ? // 獲取工作線程數(shù)量
? ? ? ? ? ? ? ? int wc = workerCountOf(c);
? ? ? ? ? ? ? ? // 判斷當(dāng)前線程池中工作線程數(shù)量是否大于線程容量,大于核心線程數(shù)或最大線程數(shù)
? ? ? ? ? ? ? ? if (wc >= CAPACITY ||
? ? ? ? ? ? ? ? ? ? wc >= (core ? corePoolSize : maximumPoolSize))
? ? ? ? ? ? ? ? ? ? // 滿足條件,說明當(dāng)前線程不是適合添加新的線程的
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? // 如果工作數(shù)量少于最大量或者核心線程數(shù)或最大線程數(shù), 工作線程數(shù)加1,即操作ctl,通過cas的方式
? ? ? ? ? ? ? ? if (compareAndIncrementWorkerCount(c))
? ? ? ? ? ? ? ? ? ? // 如果添加成功,跳出內(nèi)循環(huán),
? ? ? ? ? ? ? ? ? ? break retry;
? ? ? ? ? ? ? ? // 如果添加失敗,重新獲取ctl
? ? ? ? ? ? ? ? c = ctl.get(); ?// Re-read ctl
? ? ? ? ? ? ? ? // 判斷此時(shí)線程池狀態(tài)是否已經(jīng)改變
? ? ? ? ? ? ? ? if (runStateOf(c) != rs)
? ? ? ? ? ? ? ? ? ? //如果狀態(tài)不一致,跳過,重新循環(huán)
? ? ? ? ? ? ? ? ? ? continue retry;
? ? ? ? ? ? ? ? // else CAS failed due to workerCount change; retry inner loop
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? boolean workerStarted = false;
? ? ? ? boolean workerAdded = false;
? ? ? ? // 創(chuàng)建一個(gè)線程包裝對象,用于包裝線程
? ? ? ? Worker w = null;
? ? ? ? try {
? ? ? ? ? ? w = new Worker(firstTask);
? ? ? ? ? ? // 創(chuàng)建一個(gè)worker 工作線程
? ? ? ? ? ? final Thread t = w.thread;
? ? ? ? ? ? // 判斷創(chuàng)建的線程是否為空
? ? ? ? ? ? if (t != null) {
? ? ? ? ? ? ? ? ?// 如果不為空,獲取鎖對象
? ? ? ? ? ? ? ? final ReentrantLock mainLock = this.mainLock;
? ? ? ? ? ? ? ? // 開始加鎖
? ? ? ? ? ? ? ? mainLock.lock();
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? // 獲取線程池狀態(tài)
? ? ? ? ? ? ? ? ? ? int rs = runStateOf(ctl.get());
? ? ? ? ? ? ? ? ? ? // 如果線程池狀態(tài)是running或者線程池狀態(tài)關(guān)閉并且傳入的線程是空的
? ? ? ? ? ? ? ? ? ? if (rs < SHUTDOWN ||
? ? ? ? ? ? ? ? ? ? ? ? (rs == SHUTDOWN && firstTask == null)) {
? ? ? ? ? ? ? ? ? ? ? ? // 判斷創(chuàng)建的工作線程是否是活動(dòng)狀態(tài)(已經(jīng)開始還沒有死掉)
? ? ? ? ? ? ? ? ? ? ? ? if (t.isAlive()) // precheck that t is startable
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果是活動(dòng)狀態(tài),拋出 非法線程狀態(tài)異常?
? ? ? ? ? ? ? ? ? ? ? ? ? ? throw new IllegalThreadStateException();
? ? ? ? ? ? ? ? ? ? ? ? // 如果不是活動(dòng)狀態(tài), 添加到set集合中,這個(gè)set集合只有持有mainlock才可以訪問
? ? ? ? ? ? ? ? ? ? ? ? workers.add(w);
? ? ? ? ? ? ? ? ? ? ? ? // 獲取集合長度
? ? ? ? ? ? ? ? ? ? ? ? int s = workers.size();
? ? ? ? ? ? ? ? ? ? ? ? // 如果存放剛才創(chuàng)建的workers工作線程的集合中的線程數(shù)超過最大的池的大小
? ? ? ? ? ? ? ? ? ? ? ? if (s > largestPoolSize)
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 把set集合中的數(shù)量代替原線程池最大值
? ? ? ? ? ? ? ? ? ? ? ? ? ? largestPoolSize = s;
? ? ? ? ? ? ? ? ? ? ? ? workerAdded = true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? ? ? // 釋放鎖
? ? ? ? ? ? ? ? ? ? mainLock.unlock();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // 根據(jù)前面的判斷是否需要開啟線程,如果線程已經(jīng)是活動(dòng)的,不需要開啟,如果不是活動(dòng)線程,開啟線程
? ? ? ? ? ? ? ? if (workerAdded) {
? ? ? ? ? ? ? ? ? ? t.start();
? ? ? ? ? ? ? ? ? ? // 開啟成功,設(shè)置workerStarted 為 true
? ? ? ? ? ? ? ? ? ? workerStarted = true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? } finally {
? ? ? ? ? ? // 如果工作線程開啟失敗,調(diào)用添加到失敗的線程中
? ? ? ? ? ? if (! workerStarted)
? ? ? ? ? ? ? ? // 從set中移除失敗的線程,并且ctl減1, 并且嘗試終止線程池
? ? ? ? ? ? ? ? addWorkerFailed(w);
? ? ? ? }
? ? ? ? return workerStarted;
? ? }
? ? // 線程開啟失敗后的方法
? ? private void addWorkerFailed(Worker w) {
? ? ? ? // 獲取鎖
? ? ? ? final ReentrantLock mainLock = this.mainLock;
? ? ? ? mainLock.lock();
? ? ? ? try {
? ? ? ? ? ? if (w != null)
? ? ? ? ? ? ? ? // 如果線程不為空,從set集合中移除沒有開啟成功的線程
? ? ? ? ? ? ? ? workers.remove(w);
? ? ? ? ? ? // 減去之前ctl增加的1
? ? ? ? ? ? decrementWorkerCount();
? ? ? ? ? ? // 嘗試中斷線程
? ? ? ? ? ? tryTerminate();
? ? ? ? } finally {
? ? ? ? ? ? mainLock.unlock();
? ? ? ? }
? ? }
? ? // 通過cas方式ctl加1
? ? private boolean compareAndIncrementWorkerCount(int expect) {
? ? ? ? return ctl.compareAndSet(expect, expect + 1);
? ? }
? ? // 移除線程
? ? public boolean remove(Runnable task) {
? ? ? ? // 從等待隊(duì)列中一尺線程
? ? ? ? boolean removed = workQueue.remove(task);
? ? ? ? // 嘗試終止線程池
? ? ? ? tryTerminate(); // In case SHUTDOWN and now empty
? ? ? ? return removed;
? ? }
? ? // 使用拒絕處理對象執(zhí)行拒接指定線程
? ? final void reject(Runnable command) {
? ? ? ? handler.rejectedExecution(command, this);
? ? }

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論