文章目录
- 1、线程的异常处理
- 1.1、线程异常介绍
- 1.2、线程异常处理器
- 1.3、线程组异常处理
- 1.4、默认全局线程异常处理器
- 2、线程池异常处理
- 2.1、线程池execute方法
- 2.1.1、单独catch处理
- 2.1.2、继承ThreadPoolExecutor重写afterExecute方法
- 2.1.3、使用Thread.setUncaughtExceptionHandler方法设置异常处理器
- 2.1.4、使用ThreadGroup重写uncaughtException方法
- 2.2、线程池submit方法
- 2.2.1 catch处理
- 2.2.2 Futrue#get处理
- 3、定时任务线程池异常处理
1、线程的异常处理
1.1、线程异常介绍
先观察下面一段代码
public class ThreadTest {
public static void main(String[] args) {
Runnable runnable = () -> {
System.out.println(5 / 0);
System.out.println(11111);
};
try {
new Thread(runnable).start();
} catch (Exception e) {
System.out.println("外部抓取异常");
e.printStackTrace();
}
}
}
运行此段代码,会抛出一个异常,线程断开。结果如下:
Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadTest.lambda$main$0(ThreadTest.java:12)
at java.base/java.lang.Thread.run(Thread.java:834)
Process finished with exit code 0
可看到异常抛出在Runable内部,而不会被外部的catch抓取到,因为线程是独立执行的代码片断,线程的问题应该由线程自己来解决,在Java中,线程方法的异常都应该在线程代码边界之内进行处理。
查看Runable的源码会发现并没有throws异常,所以无法向外抛出异常。
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
需要注意的是,在线程内部,如果有检查异常,是一定需要catch处理的,不然会编译不过。
在多线程开发中,线程内部出现异常一般需要通过打日志的方式记录异常
public class ThreadTest2 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadTest2.class);
public static void main(String[] args) {
Runnable runnable = () -> {
try {
System.out.println(5 / 0);
System.out.println(11111);
} catch (Exception e) {
LOGGER.error("执行异常", e);
}
};
new Thread(runnable).start();
}
}
1.2、线程异常处理器
按照1.1打印日志的方式,每个线程都要编写一段异常处理逻辑,会出现很多重复代码,可以使用Thread的UncaughtExceptionHandler接口实现异常处理。
如下所示:
public class ThreadTest3 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadTest3.class);
public static void main(String[] args) {
Runnable runnable1 = () -> {
System.out.println(5 / 0);
System.out.println(11111);
};
Runnable runnable2 = () -> {
int[] ints = new int[1];
System.out.println(ints[2]);
};
CustomExceptionHandler customExceptionHandler = new CustomExceptionHandler();
Thread thread1 = new Thread(runnable1);
Thread thread2 = new Thread(runnable2);
thread1.setUncaughtExceptionHandler(customExceptionHandler);
thread2.setUncaughtExceptionHandler(customExceptionHandler);
thread1.start();
thread2.start();
}
public static class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("线程执行异常", e);
}
}
}
输出如下:
18:19:21.653 [Thread-1] ERROR com.iscas.biz.test.thread.exception.ThreadTest3 - 线程执行异常
java.lang.ArrayIndexOutOfBoundsException: Index 2 out of bounds for length 1
at com.iscas.biz.test.thread.exception.ThreadTest3.lambda$main$1(ThreadTest3.java:22) ~[classes/:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
18:19:21.653 [Thread-0] ERROR com.iscas.biz.test.thread.exception.ThreadTest3 - 线程执行异常
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadTest3.lambda$main$0(ThreadTest3.java:17) ~[classes/:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
Process finished with exit code 0
当一个线程由于未捕获异常而退出时,JVM会把这个事件报告给应用程序提供的UncaughtExceptionHandler异常处理器,注意的是如果在Runnable内将异常catch处理了,就不会在进入异常处理器了。
1.3、线程组异常处理
public class ThreadTest5 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadTest5.class);
public static void main(String[] args) {
Runnable runnable1 = () -> {
System.out.println(5 / 0);
System.out.println(11111);
};
ThreadGroup threadGroup = new ThreadGroup("threadGroup") {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("全局线程异常处理:线程执行异常", e);
}
};
Thread thread1 = new Thread(threadGroup, runnable1);
thread1.start();
}
}
执行结果:
19:14:19.188 [Thread-0] ERROR com.iscas.biz.test.thread.exception.ThreadTest5 - 全局线程异常处理:线程执行异常
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadTest5.lambda$main$0(ThreadTest5.java:17) ~[classes/:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
Process finished with exit code 0
1.4、默认全局线程异常处理器
还可以设置一个全局的异常处理,如果没有在线程内部catch处理,也没有为线程定义UncaughtExceptionHandler,会应用此全局处理。
public class ThreadTest4 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadTest4.class);
public static void main(String[] args) {
Runnable runnable1 = () -> {
System.out.println(5 / 0);
System.out.println(11111);
};
Runnable runnable2 = () -> {
int[] ints = new int[1];
System.out.println(ints[2]);
};
Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler2());
CustomExceptionHandler customExceptionHandler = new CustomExceptionHandler();
Thread thread1 = new Thread(runnable1);
Thread thread2 = new Thread(runnable2);
thread1.setUncaughtExceptionHandler(customExceptionHandler);
thread1.start();
thread2.start();
}
public static class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("线程执行异常", e);
}
}
public static class CustomExceptionHandler2 implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("全局线程异常处理:线程执行异常", e);
}
}
}
执行结果:
19:09:01.687 [Thread-0] ERROR com.iscas.biz.test.thread.exception.ThreadTest4 - 线程执行异常
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadTest4.lambda$main$0(ThreadTest4.java:17) ~[classes/:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
19:09:01.687 [Thread-1] ERROR com.iscas.biz.test.thread.exception.ThreadTest4 - 全局线程异常处理:线程执行异常
java.lang.ArrayIndexOutOfBoundsException: Index 2 out of bounds for length 1
at com.iscas.biz.test.thread.exception.ThreadTest4.lambda$main$1(ThreadTest4.java:22) ~[classes/:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
Process finished with exit code 0
2、线程池异常处理
2.1、线程池execute方法
线程池使用execute方法如果未catch非检查异常,会显示异常,跟单独使用Thread的情况差不多,
public class ThreadPoolTest1 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolTest1.class);
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3000, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.AbortPolicy());
AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();
executor.execute(() -> {
threadAtomicReference.set(Thread.currentThread());
System.out.println("线程内部:" + threadAtomicReference.get().getState());
System.out.println(4 / 0);
});
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程外部:" + threadAtomicReference.get().getState());
}
}
输出:
线程内部:RUNNABLE
Exception in thread "pool-2-thread-1" java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolTest1.lambda$main$0(ThreadPoolTest1.java:27)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
线程外部:TERMINATED
要记录或处理这种情况线程的异常情况,采用以下几种方式
2.1.1、单独catch处理
public class ThreadPoolTest1 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolTest1.class);
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3000, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.AbortPolicy());
AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();
executor.execute(() -> {
threadAtomicReference.set(Thread.currentThread());
System.out.println("线程内部:" + threadAtomicReference.get().getState());
try {
System.out.println(4 / 0);
} catch (Exception e) {
LOGGER.error("执行异常", e);
}
});
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程外部:" + threadAtomicReference.get().getState());
}
}
输出:
线程内部:RUNNABLE
19:32:26.907 [pool-2-thread-1] ERROR com.iscas.biz.test.thread.exception.ThreadPoolTest1 - 执行异常
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolTest1.lambda$main$0(ThreadPoolTest1.java:28) ~[classes/:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
线程外部:WAITING
这样处理会有个问题,不管有没有抛出异常都需要在Runnable内将代码块catch起来,因为可能会存在非检查异常,如果不catch会漏掉日志。
这里显示watting是因为任务执行完毕,线程池中会保持核心线程池的个数处于等待状态 waiting。
2.1.2、继承ThreadPoolExecutor重写afterExecute方法
public class ThreadPoolTest2 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolTest2.class);
public static void main(String[] args) {
ThreadPoolExecutor executor = new CustomThreadPoolExecutor(1, 2, 3000, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.AbortPolicy());
AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();
executor.execute(() -> {
threadAtomicReference.set(Thread.currentThread());
System.out.println("线程内部:" + threadAtomicReference.get().getState());
System.out.println(4 / 0);
});
try {
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程外部:" + threadAtomicReference.get().getState());
}
public static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull ThreadFactory threadFactory, @NotNull RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
LOGGER.error("执行异常", t);
}
}
}
输出:
线程内部:RUNNABLE
19:40:20.094 [pool-2-thread-1] ERROR com.iscas.biz.test.thread.exception.ThreadPoolTest2 - 执行异常
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolTest2.lambda$main$0(ThreadPoolTest2.java:26) ~[classes/:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
Exception in thread "pool-2-thread-1" java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolTest2.lambda$main$0(ThreadPoolTest2.java:26)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
线程外部:TERMINATED
2.1.3、使用Thread.setUncaughtExceptionHandler方法设置异常处理器
使用线程池构造器中的线程工厂设置异常处理器
public class ThreadPoolTest3 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolTest3.class);
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3000, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadFactory() {
@Override
public Thread newThread(@NotNull Runnable r) {
Thread thread = new Thread(r);
thread.setName("customFactory-");
thread.setUncaughtExceptionHandler(new CustomExceptionHandler());
return thread;
}
}, new ThreadPoolExecutor.AbortPolicy());
AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();
executor.execute(() -> {
threadAtomicReference.set(Thread.currentThread());
System.out.println("线程内部:" + threadAtomicReference.get().getState());
System.out.println(4 / 0);
});
try {
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程外部:" + threadAtomicReference.get().getState());
}
public static class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("线程执行异常", e);
}
}
}
输出:
线程内部:RUNNABLE
19:48:05.045 [customFactory-] ERROR com.iscas.biz.test.thread.exception.ThreadPoolTest3 - 线程执行异常
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolTest3.lambda$main$0(ThreadPoolTest3.java:34) ~[classes/:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
线程外部:TERMINATED
2.1.4、使用ThreadGroup重写uncaughtException方法
public class ThreadPoolTest4 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolTest4.class);
public static void main(String[] args) {
ThreadGroup threadGroup = new ThreadGroup("threadGroup"){
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("执行异常", e);
}
};
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3000, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), r -> new Thread(threadGroup, r), new ThreadPoolExecutor.AbortPolicy());
AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();
executor.execute(() -> {
threadAtomicReference.set(Thread.currentThread());
System.out.println("线程内部:" + threadAtomicReference.get().getState());
System.out.println(4 / 0);
});
try {
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程外部:" + threadAtomicReference.get().getState());
}
}
输出:
线程内部:RUNNABLE
19:52:10.599 [Thread-0] ERROR com.iscas.biz.test.thread.exception.ThreadPoolTest4 - 执行异常
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolTest4.lambda$main$1(ThreadPoolTest4.java:33) ~[classes/:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
线程外部:TERMINATED
2.2、线程池submit方法
线程池如果调用的时submit方法,会返回一个Futrue,如果不进行任何处理,不会显示异常。
public class ThreadPoolSubmitTest1 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolSubmitTest1.class);
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3000, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.AbortPolicy());
AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();
executor.submit(() -> {
threadAtomicReference.set(Thread.currentThread());
System.out.println("线程内部:" + threadAtomicReference.get().getState());
System.out.println(4 / 0);
});
try {
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程外部:" + threadAtomicReference.get().getState());
}
这种情况有两种方式,一种是在线程内部catch,一种是通过Futrue#get()进行异常catch处理
2.2.1 catch处理
public class ThreadPoolSubmitTest2 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolSubmitTest2.class);
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3000, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.AbortPolicy());
AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();
executor.submit(() -> {
threadAtomicReference.set(Thread.currentThread());
try {
System.out.println("线程内部:" + threadAtomicReference.get().getState());
System.out.println(4 / 0);
} catch (Exception e) {
LOGGER.error("执行异常", e);
}
});
try {
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程外部:" + threadAtomicReference.get().getState());
}
}
输出
线程内部:RUNNABLE
19:58:41.961 [pool-2-thread-1] ERROR com.iscas.biz.test.thread.exception.ThreadPoolSubmitTest2 - 执行异常
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolSubmitTest2.lambda$main$0(ThreadPoolSubmitTest2.java:29) ~[classes/:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
线程外部:WAITING
2.2.2 Futrue#get处理
public class ThreadPoolSubmitTest3 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolSubmitTest3.class);
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3000, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.AbortPolicy());
AtomicReference<Thread> threadAtomicReference = new AtomicReference<>();
Future<?> future = executor.submit(() -> {
threadAtomicReference.set(Thread.currentThread());
System.out.println("线程内部:" + threadAtomicReference.get().getState());
System.out.println(4 / 0);
});
try {
future.get();
} catch (Exception e) {
LOGGER.error("执行异常", e);
}
try {
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程外部:" + threadAtomicReference.get().getState());
}
}
输出
线程内部:RUNNABLE
20:00:53.102 [main] ERROR com.iscas.biz.test.thread.exception.ThreadPoolSubmitTest3 - 执行异常
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
at java.util.concurrent.FutureTask.report(FutureTask.java:122) ~[?:?]
at java.util.concurrent.FutureTask.get(FutureTask.java:191) ~[?:?]
at com.iscas.biz.test.thread.exception.ThreadPoolSubmitTest3.main(ThreadPoolSubmitTest3.java:29) ~[classes/:?]
Caused by: java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolSubmitTest3.lambda$main$0(ThreadPoolSubmitTest3.java:26) ~[classes/:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
线程外部:WAITING
注意哈,与Runnable对应的Callable内的call的接口有throws异常。
3、定时任务线程池异常处理
需要注意,一旦ScheduledExecutorService执行的逻辑中抛出异常,那么调度会自动停止,并且不会有任何提示信息。在其scheduleWithFixedDelay()和scheduleAtFixedRate()方法都是如此。
这种方式不能使用异常处理器处理,可以使用catch处理
public class ThreadPoolSchedulerTest2 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolSchedulerTest2.class);
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
executor.scheduleAtFixedRate(() -> {
try {
System.out.println(111);
System.out.println(4 / 0);
} catch (Exception e) {
LOGGER.error("执行出错", e);
}
}, 1, 2, TimeUnit.SECONDS);
}
}
输出
111
20:31:38.173 [pool-2-thread-2] ERROR com.iscas.biz.test.thread.exception.ThreadPoolSchedulerTest2 - 执行出错
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolSchedulerTest2.lambda$main$0(ThreadPoolSchedulerTest2.java:25) ~[classes/:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) ~[?:?]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
111
20:31:40.178 [pool-2-thread-2] ERROR com.iscas.biz.test.thread.exception.ThreadPoolSchedulerTest2 - 执行出错
java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolSchedulerTest2.lambda$main$0(ThreadPoolSchedulerTest2.java:25) ~[classes/:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) ~[?:?]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]
注意的是使用Future#get处理异常,定时任务不会继续执行,测试如下:
public class ThreadPoolSchedulerTest1 {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolSchedulerTest1.class);
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
ScheduledFuture<?> future = executor.scheduleAtFixedRate(() -> {
System.out.println(1111);
System.out.println(4 / 0);
}, 1, 2, TimeUnit.SECONDS);
try {
future.get();
} catch (Exception e) {
LOGGER.error("执行异常", e);
}
}
}
输出:
1111
20:32:51.159 [main] ERROR com.iscas.biz.test.thread.exception.ThreadPoolSchedulerTest1 - 执行异常
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
at java.util.concurrent.FutureTask.report(FutureTask.java:122) ~[?:?]
at java.util.concurrent.FutureTask.get(FutureTask.java:191) ~[?:?]
at com.iscas.biz.test.thread.exception.ThreadPoolSchedulerTest1.main(ThreadPoolSchedulerTest1.java:28) ~[classes/:?]
Caused by: java.lang.ArithmeticException: / by zero
at com.iscas.biz.test.thread.exception.ThreadPoolSchedulerTest1.lambda$main$0(ThreadPoolSchedulerTest1.java:25) ~[classes/:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) ~[?:?]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:834) ~[?:?]