今天小夥伴遇到個小問題,執行緒池提交的任務如果沒有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...