집행자로부터 runtimeexections를 올바르게 잡는 방법은 무엇입니까?
-
18-09-2019 - |
문제
다음 코드가 있다고 말합니다.
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);
이제 myRunnable
던지는 a RuntimeExcpetion
, 어떻게 잡을 수 있습니까? 한 가지 방법은 내 자신을 공급하는 것입니다 ThreadFactory
구현 newSingleThreadExecutor()
그리고 사용자 정의를 설정하십시오 uncaughtExceptionHandler
s에 대한 s Thread
그것에서 나오는 s. 또 다른 방법은 포장하는 것입니다 myRunnable
현지 (익명) Runnable
여기에는 try -catch -block이 포함되어 있습니다. 어쩌면 다른 유사한 해결 방법도있을 수 있습니다. 그러나 ... 어떻게 든 이것은 더러워진 느낌이 든다. 나는 그것이 복잡하지 않아야한다고 생각한다. 깨끗한 솔루션이 있습니까?
해결책
깨끗한 해결 방법은 사용하는 것입니다 ExecutorService.submit()
대신에 execute()
. 이것은 당신을 반환합니다 Future
작업의 결과 또는 예외를 검색하는 데 사용할 수 있습니다.
ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable task = new Runnable() {
public void run() {
throw new RuntimeException("foo");
}
};
Future<?> future = executor.submit(task);
try {
future.get();
} catch (ExecutionException e) {
Exception rootException = e.getCause();
}
다른 팁
런타임 예외를 포착하고 처리 할 수있는 다른 런 가능하게 달리기를 장식하십시오.
public class REHandler implements Runnable {
Runnable delegate;
public REHandler (Runnable delegate) {
this.delegate = delegate;
}
public void run () {
try {
delegate.run ();
} catch (RuntimeException e) {
... your fancy error handling here ...
}
}
}
executor.execute(new REHandler (myRunnable));
전화하지 않겠습니까? ExecutorService#submit()
, 얻으십시오 Future
뒤로 그리고 전화 할 때 가능한 예외를 직접 처리하십시오 Future#get()
?
Skaffman은 그 사용에서 정확합니다 submit
가장 깨끗한 접근법입니다. 대안적인 접근법은 서브 클래스입니다 ThreadPoolExecutor
그리고 무시합니다 afterExecute(Runnable, Throwable)
. 이 접근법을 따르는 경우 반드시 전화하십시오 execute(Runnable)
보다는 submit(Runnable)
또는 afterExecute
호출되지 않습니다.
API 설명에 따라 :
주어진 실행 가능의 실행이 완료되면 메소드가 호출되었습니다. 이 방법은 작업을 실행 한 스레드에 의해 호출됩니다. 널이 아닌 경우, 던질 수있는 사람은 잡을 수 없습니다
RuntimeException
또는Error
이로 인해 실행이 갑자기 종료되었습니다.참고 : 작업 (예 : FutureTask)에 작업이 명시 적으로 또는 제출과 같은 방법을 통해 동작이 밀폐 될 때, 이러한 작업 객체는 계산 예외를 포착하고 유지하므로 갑작스런 종결을 일으키지 않으며 내부 예외는 다음과 같습니다. 이 방법으로 전달되지 않았습니다.
작업(Callable
또는 Runnable
) 제출 ThreadPoolExecutors
a로 변환됩니다 FuturnTask
, 이름이 지정된 소품이 포함되어 있습니다 callable
제출 한 작업과 같습니다. Futurntask에는 자체가 있습니다 run
다음과 같은 방법. 모든 예외 또는 던질 수있는 던지기 c.call()
붙잡아지고 이름이 지정된 소품에 넣을 것입니다 outcome
. Futurntask를 호출 할 때 get
방법, outcome
던질 것입니다
JDK1.8 소스 코드에서 Futurntask.RUN
public void run() {
...
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;
// save ex into `outcome` prop
setException(ex);
}
if (ran)
set(result);
}
}
...
}
예외를 잡으려면 :
- 1. Skaffman의 대답
- 2. ThreadPooleExecutor를 새로 사용하면`jectexecute '를 덮어 씁니다
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
Throwable cause = null;
if (t == null && r instanceof Future) {
try {
((Future<?>) r).get();
} catch (InterruptedException | ExecutionException e) {
cause = e;
}
} else if (t != null) {
cause = t;
}
if (cause != null) {
// log error
}
}