如何捕获线程池执行产生的异常
1.如何捕获线程池执行产生的异常
就像例子1中所写的那样,executor执行一个Runnable接口,在Runnable的实现lambda表达式中try catch了异常之后,是没办法throw e往外抛出异常的。在main线程中想catch住线程池执行的异常,也catch不到。如果这样写是不行的,体会一下:
package com.test.thread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestThread {
private static ExecutorService executor = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
try {
CountDownLatch downLatch = new CountDownLatch(5);
for (int i = 5; i >= 0; i--) {
executor.submit(divide(i, downLatch));
}
downLatch.await();
} catch (Exception e) {
System.out.println("main出错了!" + e.getMessage());
e.printStackTrace();
}
System.out.println("main运行结束了!");
executor.shutdown();
}
private static Runnable divide(int a, CountDownLatch downLatch) {
return () -> {
try {
int b = 100 / a;
Thread.sleep(5000);
System.out.println("a = " + a + " 算出b=" + b);
} catch (Exception e) {
e.printStackTrace();
System.out.println("divide出错了!");
} finally {
downLatch.countDown();
}
};
}
}
所以改为executor.submit提交一个Callable带返回值的任务(Callable可以抛出异常),是否执行失败返回不同的值,submit提交返回future,然后检查返回值,如果失败,手动抛出异常
例子2:
package com.test.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestThread2 {
private static ExecutorService executor = Executors.newFixedThreadPool(5);
//线程执行成功
private static final int THREAD_EXECUTE_OK = 1;
//线程执行失败
private static final int THREAD_EXECUTE_FAILED = 0;
public static void main(String[] args) {
try {
CountDownLatch downLatch = new CountDownLatch(5);
List<Future<Integer>> futureList = new ArrayList<>();
for (int i = 5; i >= 0; i--) {
Future<Integer> f = executor.submit(divide(i, downLatch));
futureList.add(f);
}
System.out.println("各线程执行中...");
downLatch.await();
System.out.println("各线程执行完毕");
//检查多线程是否有执行失败
for (Future<Integer> future : futureList) {
Integer state = future.get();
if (THREAD_EXECUTE_FAILED == state) {
throw new RuntimeException("有线程执行失败!");
}
}
} catch (Exception e) {
System.out.println("main出错了!" + e.getMessage());
e.printStackTrace();
}
System.out.println("main运行结束了!");
executor.shutdown();
}
private static Callable<Integer> divide(int a, CountDownLatch downLatch) {
return () -> {
try {
System.out.println("线程-" + Thread.currentThread() + "正在计算 100 / " + a);
int b = 100 / a;
Thread.sleep(5000);
System.out.println("a = " + a + " 算出b=" + b + " 线程-" + Thread.currentThread() + "执行完毕");
} catch (Exception e) {
e.printStackTrace();
System.out.println("divide出错了!");
return 0;
} finally {
downLatch.countDown();
}
return 1;
};
}
/**
* 检查多线程是否执行完毕
*/
public boolean isTheadPoolDone(List<Future<?>> futureList) {
boolean endFlag = true;
if (null != futureList && futureList.size() > 0) {
for (Future<?> future : futureList) {
if (!future.isDone()) {
endFlag = false;
break;
}
}
}
return endFlag;
}
}
console:
各线程执行中...
线程-Thread[pool-1-thread-5,5,main]正在计算 100 / 1
线程-Thread[pool-1-thread-4,5,main]正在计算 100 / 2
线程-Thread[pool-1-thread-1,5,main]正在计算 100 / 5
线程-Thread[pool-1-thread-3,5,main]正在计算 100 / 3
线程-Thread[pool-1-thread-2,5,main]正在计算 100 / 4
a = 2 算出b=50 线程-Thread[pool-1-thread-4,5,main]执行完毕
a = 1 算出b=100 线程-Thread[pool-1-thread-5,5,main]执行完毕
a = 4 算出b=25 线程-Thread[pool-1-thread-2,5,main]执行完毕
a = 3 算出b=33 线程-Thread[pool-1-thread-3,5,main]执行完毕
线程-Thread[pool-1-thread-5,5,main]正在计算 100 / 0
a = 5 算出b=20 线程-Thread[pool-1-thread-1,5,main]执行完毕
各线程执行完毕
divide出错了!
main出错了!有线程执行失败!
main运行结束了!
java.lang.ArithmeticException: / by zero
at com.test.thread.TestThread2.lambda$divide$0(TestThread2.java:56)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
java.lang.RuntimeException: 有线程执行失败!
at com.test.thread.TestThread2.main(TestThread2.java:40)
Process finished with exit code 0
--