深度解析Java執行緒池的異常處理機制

2021-09-11 13:27:50 字數 3402 閱讀 6784

今天小夥伴遇到個小問題,執行緒池提交的任務如果沒有catch異常,那麼會拋到**去,之前倒是沒研究過,本著實事求是的原則,看了一下**。

考慮下面這段**,有什麼區別呢?你可以猜猜會不會有異常打出呢?如果打出來的話是在**?:

executorservice threadpool = executors.newfixedthreadpool(1);

threadpool.submit(() -> );

threadpool.execute(() -> );複製**

我們下面就來看下**, 其實就是將我們提交過去的runnable包裝成乙個future

public future<?> submit(runnable task) 

protected

runnablefuturenewtaskfor

(runnable runnable, t value)

public

futuretask

(runnable runnable, v result)

public

static

callablecallable

(runnable task, t result)

static

final

class

runnableadapter

implements

callable

public t call

() }複製**

接下來就會實際提交到佇列中交給執行緒池排程處理:

/**

* **還是很清爽的,乙個很典型的生產者/消費者模型,

* 這裡暫不糾結這些細節,那麼如果提交到workqueue成功的話,消費者是誰呢?

* 明顯在這個newworker裡搞的鬼,同樣細節有興趣可以自己再去研究,這裡我們會發現

* 核心就是worker這個內部類

*/public

void

execute

(runnable command)

if (isrunning(c) && workqueue.offer(command))

else

if (!addworker(command, false))

reject(command);

}複製**

那麼接下來看看執行緒池核心的流程:

private

final

class

worker

extends

abstractqueuedsynchronizer

implements

runnable

}final

void

runworker

(worker w)

catch (runtimeexception x) catch (error x) catch (throwable x) finally

} finally

}completedabruptly = false;

} finally

}複製**

那麼我們可以這裡是直接呼叫的run方法,先看submit的方式,我們知道最終傳遞過去的是乙個futuretask,也就是說會呼叫這裡的run方法,我們看看實現:

public

void

run()

catch (throwable ex)

if (ran)

set(result);

}} finally

protected

void

setexception

(throwable t)

}複製**

可以看到其實類似於直接吞掉了,這樣的話我們呼叫get()方法的時候會拿到, 比如我們可以重寫afterexecute方法,從而可以得到實際的異常:

protected

void

afterexecute

(runnable r, throwable t)

catch (cancellationexception ce) catch (executionexception ee) catch (interruptedexception ie)

}if (t != null)

}複製**

那麼如果是直接exeture的方式有啥不同呢?這樣的話傳遞過去的就直接是runnable,因此就會直接丟擲:

try  catch (runtimeexception x)  catch (error x)  catch (throwable x)  finally 複製**
那麼這裡的異常到底會丟擲到**呢, 我們看看jvm具體是怎麼處理的:

if (!destroy_vm || jdk_version::is_jdk12x_version())  else 

if (has_pending_exception)

}}複製**

可以看到這裡最終會去呼叫thread#dispatchuncaughtexception方法:

private

void

dispatchuncaughtexception

(throwable e)

複製**

public

void

uncaughtexception

(thread t, throwable e)

else else

if (!(e instanceof threaddeath))

}}複製**

這裡如果環境是tomcat的話最終會打到catalina.out:

_6145c123-4ec7-4856-b106-6c61e6dca285

對於執行緒池、包括執行緒的異常處理推薦一下方式:

1 直接try/catch,個人 基本都是用這種方式

2 執行緒直接重寫整個方法:

thread t = new thread();

t.setuncaughtexceptionhandler(new thread.uncaughtexceptionhandler()

});//如果是執行緒池的模式:

executorservice threadpool = executors.newfixedthreadpool(1, r -> );複製**

3 也可以直接重寫protected void afterexecute(runnable r, throwable t)方法

解析Java執行緒池的異常處理機制

今天小夥伴遇到個小問題,執行緒池提交的任務如果沒有catch異常,那麼會拋到 去,之前倒是沒研究過,本著實事求是的原則,看了一下 考慮下面這段 有什麼區別呢?你可以猜猜會不會有異常打出呢?如果打出來的話是在 executorservice threadpool executors.newfixedt...

Java執行緒池異常處理原理

executorservice exec executors.newfixedthreadpool 8 以上述 為例,得到executorservice例項後,我們可以通過兩種方式提交任務 runnable exec.execute runnable 和 exec.submit runnable e...

java 執行緒池 異常 處理 機制 分析

public class threadtest success trycatch exception e 上述 只有在呼叫get 時丟擲異常,否則不列印任何異常資訊,檢視原始碼得到原因如下 public futuresubmit runnable task,v result executorcomp...