ScheduledExecutorService 的任务抛出异常时不打印堆栈跟踪
No stack trace is printed when ScheduledExecutorService's task throws an exception
我正在通过 Dropwizard 的 LifecycleEnvironment.scheduledExecutorService()
创建一个 ScheduledExecutorService。我在上面安排了四个任务,它们在 3 秒后抛出异常。问题是没有为异常打印堆栈跟踪,因此我无法追踪它发生的原因。抛出异常一的任务永远不会重新启动。
我尝试设置一个默认的未捕获异常处理程序,但它也没有帮助:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
System.err.println("An exception occurred as below:");
throwable.printStackTrace(System.err);
}
});
完整代码如下:
这是扩展应用程序的主要驱动 class:
App.java
import io.dropwizard.Application;
import io.dropwizard.setup.Environment;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class App extends Application<AppConfiguration> {
public void run(AppConfiguration appConfiguration, Environment environment) throws Exception {
final ScheduledExecutorService scheduledExecutorService = environment.lifecycle()
.scheduledExecutorService("throwing-exception-threads").threads(4)
.build();
scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
final HelloWorldResource resource = new HelloWorldResource();
environment.jersey().register(resource);
}
public static void main(String[] args) throws Exception {
new App().run(args);
}
}
按固定时间间隔安排任务的代码如下。它打印每秒递增的计数器值。当计数器为 3 时,它抛出 NullPointerException。
ThreadToDie.java
public class ThreadToDie implements Runnable {
int i = 0;
@Override
public void run() {
i++;
System.out.printf("Value of i: %d\n", i);
if (i % 3 == 0) {
System.out.printf("Throwing NullPointerException\n");
throw new NullPointerException("This should be printed.");
}
}
}
为了完整起见,以下是配置 class 和 HelloWorld API class。尽管在问题中询问它们包含的内容无关紧要。
AppConfiguration.java
import io.dropwizard.Configuration;
public class AppConfiguration extends Configuration {
}
HelloWorldResource.java
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.Optional;
@Path("/hello")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldResource {
@GET
public String hello(@QueryParam("name") Optional<String> name) {
final String retVal = String.format("Hello %s!", name.orElse("World"));
return retVal;
}
}
请参阅 Why is UncaughtExceptionHandler not called by ExecutorService? 了解为什么从未触发 UncaughtExceptionHandler
- 您提供的每个任务都由捕获所有异常的工作人员处理。
当您将任务提交给执行者时,您会收到一个 Future
并且可以通过这种方式访问异常:
ScheduledFuture<?> future = scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
try {
future.get();
} catch (ExecutionException ex) {
ex.getCause().printStackTrace();
}
Future.get
将等待任务完成或出错。
我正在通过 Dropwizard 的 LifecycleEnvironment.scheduledExecutorService()
创建一个 ScheduledExecutorService。我在上面安排了四个任务,它们在 3 秒后抛出异常。问题是没有为异常打印堆栈跟踪,因此我无法追踪它发生的原因。抛出异常一的任务永远不会重新启动。
我尝试设置一个默认的未捕获异常处理程序,但它也没有帮助:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
System.err.println("An exception occurred as below:");
throwable.printStackTrace(System.err);
}
});
完整代码如下:
这是扩展应用程序的主要驱动 class:
App.java
import io.dropwizard.Application;
import io.dropwizard.setup.Environment;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class App extends Application<AppConfiguration> {
public void run(AppConfiguration appConfiguration, Environment environment) throws Exception {
final ScheduledExecutorService scheduledExecutorService = environment.lifecycle()
.scheduledExecutorService("throwing-exception-threads").threads(4)
.build();
scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
final HelloWorldResource resource = new HelloWorldResource();
environment.jersey().register(resource);
}
public static void main(String[] args) throws Exception {
new App().run(args);
}
}
按固定时间间隔安排任务的代码如下。它打印每秒递增的计数器值。当计数器为 3 时,它抛出 NullPointerException。
ThreadToDie.java
public class ThreadToDie implements Runnable {
int i = 0;
@Override
public void run() {
i++;
System.out.printf("Value of i: %d\n", i);
if (i % 3 == 0) {
System.out.printf("Throwing NullPointerException\n");
throw new NullPointerException("This should be printed.");
}
}
}
为了完整起见,以下是配置 class 和 HelloWorld API class。尽管在问题中询问它们包含的内容无关紧要。
AppConfiguration.java
import io.dropwizard.Configuration;
public class AppConfiguration extends Configuration {
}
HelloWorldResource.java
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.Optional;
@Path("/hello")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldResource {
@GET
public String hello(@QueryParam("name") Optional<String> name) {
final String retVal = String.format("Hello %s!", name.orElse("World"));
return retVal;
}
}
请参阅 Why is UncaughtExceptionHandler not called by ExecutorService? 了解为什么从未触发 UncaughtExceptionHandler
- 您提供的每个任务都由捕获所有异常的工作人员处理。
当您将任务提交给执行者时,您会收到一个 Future
并且可以通过这种方式访问异常:
ScheduledFuture<?> future = scheduledExecutorService.scheduleAtFixedRate(new ThreadToDie(), 0,5, TimeUnit.SECONDS);
try {
future.get();
} catch (ExecutionException ex) {
ex.getCause().printStackTrace();
}
Future.get
将等待任务完成或出错。