日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

FixedThreadPool吞掉了异常

發(fā)布時(shí)間:2024/4/14 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FixedThreadPool吞掉了异常 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

FixedThreadPool吞掉了異常

為了方便遍描述問(wèn)題,如下是簡(jiǎn)化后的

public class RunException {public static void main(String[] args) {ExecutorService readerPool = Executors.newFixedThreadPool(3);readerPool.submit(new Runnable() {public void run() {throw new RuntimeException("異常");}});readerPool.shutdown();} }

此處FixedThreadPool吞掉了異常。

問(wèn)題

  • 為什么不能拋出到外部線程捕獲
  • submit為什么不能打印報(bào)錯(cuò)信息
  • execute怎么使用logger打印報(bào)錯(cuò)信息
  • 為什么不能拋出到外部線程捕獲

    jvm會(huì)在線程即將死掉的時(shí)候捕獲所有未捕獲的異常進(jìn)行處理。默認(rèn)使用的是Thread.defaultUncaughtExceptionHandler

    submit為什么不能打印報(bào)錯(cuò)信息

    public Future<?> submit(Runnable task) {if (task == null) throw new NullPointerException();RunnableFuture<Void> ftask = newTaskFor(task, null);//創(chuàng)建FutureTask類execute(ftask);return ftask;}

    查看FutureTask.run():

    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;//這里捕獲了所有異常調(diào)用setExceptionsetException(ex);}if (ran)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 interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}

    接著查看setException(ex);,將線程狀態(tài)由completing改為exceptional,并將異常信息存在outcome中:

    //這個(gè)方法就是這事線程狀態(tài)為completing -> exceptional//同時(shí)用outcome保存異常信息。protected void setException(Throwable t) {if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {outcome = t;UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final statefinishCompletion();}}

    繼續(xù)查看outcome的使用:

    //report會(huì)拋出exception信息 private V report(int s) throws ExecutionException {Object x = outcome;if (s == NORMAL)return (V)x;if (s >= CANCELLED)throw new CancellationException();throw new ExecutionException((Throwable)x);}//get會(huì)調(diào)用report()方法 public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)s = awaitDone(false, 0L);return report(s);}
  • report會(huì)拋出exception信息,但report是私有方法;
  • get會(huì)調(diào)用report()方法
  • 所以如果需要獲取異常信息就需要調(diào)用get()方法。

    execute怎么輸入logger日志

    查看execute的實(shí)現(xiàn)ThreadPoolExecutor.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);}

    從代碼可知,線程池將任務(wù)加入了任務(wù)隊(duì)列,需要看看線程在哪執(zhí)行任務(wù)的。那么只需要看看有沒(méi)有獲取任務(wù)的函數(shù),ThreadPoolExecutor.getTask()即是獲取任務(wù)的函數(shù),通過(guò)查找,ThreadPoolExecutor.runWorker調(diào)用了ThreadPoolExecutor.getTask(),它應(yīng)該是執(zhí)行任務(wù)的代碼:

    final void runWorker(Worker w) {Thread wt = Thread.currentThread();Runnable task = w.firstTask;w.firstTask = null;w.unlock(); // allow interruptsboolean completedAbruptly = true;try {while (task != null || (task = getTask()) != null) {w.lock();// If pool is stopping, ensure thread is interrupted;// if not, ensure thread is not interrupted. This// requires a recheck in second case to deal with// shutdownNow race while clearing interruptif ((runStateAtLeast(ctl.get(), STOP) ||(Thread.interrupted() &&runStateAtLeast(ctl.get(), STOP))) &&!wt.isInterrupted())wt.interrupt();try {beforeExecute(wt, task);Throwable thrown = null;try {task.run();} catch (RuntimeException x) {//這里直接拋出所有Runtime異常thrown = x; throw x;} catch (Error x) {thrown = x; throw x;} catch (Throwable x) {thrown = x; throw new Error(x);} finally {afterExecute(task, thrown);}} finally {task = null;w.completedTasks++;w.unlock();}}completedAbruptly = false;} finally {processWorkerExit(w, completedAbruptly);}}

    代碼注釋中看到獲取RuntimeException的位置了。

    這里拋出的異常在哪里處理呢? 接下來(lái)處理是交由jvm處理,從已經(jīng)學(xué)習(xí)的知識(shí)中只知道jvm調(diào)用Thread.dispatchUncaughtException來(lái)處理所有未捕獲的異常

    /*** Dispatch an uncaught exception to the handler. This method is* intended to be called only by the JVM.*/private void dispatchUncaughtException(Throwable e) {getUncaughtExceptionHandler().uncaughtException(this, e);}

    這里可以根據(jù)該方法注釋解釋,意思就是這個(gè)方法只用于JVM調(diào)用,處理線程未捕獲的異常。 繼續(xù)查看getUncaughtExceptionHandler()方法:

    public interface UncaughtExceptionHandler {svoid uncaughtException(Thread t, Throwable e);}// 處理類private volatile UncaughtExceptionHandler uncaughtExceptionHandler;// 默認(rèn)處理類private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;/*** 設(shè)置默認(rèn)的處理類,注意是靜態(tài)方法,作用域?yàn)樗芯€程設(shè)置默認(rèn)的處理類**/public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));}defaultUncaughtExceptionHandler = eh;}//獲取默認(rèn)處理類public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){return defaultUncaughtExceptionHandler;}//獲取處理類,注意不是靜態(tài)方法,只作用域該線程//處理類為空使用ThreadGrouppublic UncaughtExceptionHandler getUncaughtExceptionHandler() {return uncaughtExceptionHandler != null ?uncaughtExceptionHandler : group;}//設(shè)置處理類public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {checkAccess();uncaughtExceptionHandler = eh;}/*** Dispatch an uncaught exception to the handler. This method is* intended to be called only by the JVM.*/private void dispatchUncaughtException(Throwable e) {//獲取處理類型進(jìn)行異常處理getUncaughtExceptionHandler().uncaughtException(this, e);}

    如果線程UncaughtExceptionHandler處理器為空則threadGroup處理器 查看threadGroup:

    public void uncaughtException(Thread t, Throwable e) {if (parent != null) {parent.uncaughtException(t, e);} else {Thread.UncaughtExceptionHandler ueh =Thread.getDefaultUncaughtExceptionHandler();if (ueh != null) {ueh.uncaughtException(t, e);} else if (!(e instanceof ThreadDeath)) {System.err.print("Exception in thread \""+ t.getName() + "\" ");e.printStackTrace(System.err);}}}

    從代碼中可以看出,

  • 如果父進(jìn)程不為空,則使用父進(jìn)程處理未捕獲異常;
  • 如果無(wú)父進(jìn)程,則獲取默認(rèn)的UncaughtExceptionHandler進(jìn)行處理。
  • 默認(rèn)的UncaughtExceptionHandler為null,則使用Sytem.err將錯(cuò)誤信息輸出;
  • 默認(rèn)的UncaughtExceptionHandler不為null,則使用UncaughtExceptionHandler進(jìn)行處理。
  • 所以有兩個(gè)方法實(shí)現(xiàn)用logger輸出:

  • Thread定義uncaughtExceptionHandler:Thread.setUncaughtExceptionHandler(),該方法僅能設(shè)置某個(gè)線程的默認(rèn)UncaughtExceptionHandler。
  • Thread定義defaultUncaughtExceptionHandler:使用Thread.setDefaultUncaughtExceptionHandler,該方法設(shè)置所有線程的默認(rèn)UncaughtExceptionHandler。
  • 測(cè)試程序

    僅某個(gè)線程設(shè)置默認(rèn)UncaughtExceptionHandler

    public static void oneThreadUncaughtExceptionHandler() {Thread t1 = new Thread(() -> {throw new RuntimeException(" t1 runtime exception");}, "t1");t1.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println(Thread.currentThread() + "trigger uncaugh exception handler");}});t1.start();Thread t2 = new Thread(() -> {throw new RuntimeException(" t2 runtime exception");}, "t2");t2.start();}

    設(shè)置defaultUncaughtExceptionHandler

    public static void defaultThreadUncaughtExceptionHandler() {Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println(Thread.currentThread() + "trigger uncaugh exception handler");}});new Thread(() -> {throw new RuntimeException(" t1 runtime exception");}, "t1").start();new Thread(() -> {throw new RuntimeException(" t2 runtime exception");}, "t2").start();}

    解惑

    那為什么我們的例子代碼中,異常不會(huì)輸出呢?應(yīng)該有兜底的System.err來(lái)輸出異常才對(duì)。 不是這樣的,我們的例子中的異常實(shí)際上是處理了的,它捕獲了異常,并且保存到了outcome中。僅僅有未捕獲的異常,JVM才會(huì)調(diào)用Thread.dispatchUncaughtException來(lái)處理。

    轉(zhuǎn)載于:https://my.oschina.net/hgfdoing/blog/3043237

    超強(qiáng)干貨來(lái)襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

    總結(jié)

    以上是生活随笔為你收集整理的FixedThreadPool吞掉了异常的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。