简单谈谈线程池在使用过程中出现异常的一些处理策略,合理使用线程池,必须能够识别主线程与线程池直接的关系、充分了解线程池机制,发挥优点,了解盲区,合理利用不留坑。
先demo几个例子,有时间展开论述下使用场景和异常处理。
/**
* created by guanjian on 2020/6/18 15:30
*/
public class ThreadPoolExecutorTest extends BaseTest {
@Resource
private ThreadPoolTaskExecutor taskExecutor;
@Test
public void execute() {
System.out.println("BEGIN-execute");
IntStream.range(0, 10).forEach(x ->
taskExecutor.execute(() -> {
//子线程异常抛出,不会阻塞主线程,而且可以立刻看到异常
throw new RuntimeException("error");
}
)
);
System.out.println("END-execute");
}
@Test
public void execute_countDownLatch() {
System.out.println("BEGIN-execute-countDownLatch");
final CountDownLatch cdl = new CountDownLatch(10);
IntStream.rangeClosed(0, 10).forEach(x ->
taskExecutor.execute(() -> {
try {
throw new RuntimeException("error");
} finally {
//如果使用多线程处理,必须用finally处理cdl.countDown(),以免子线程处理异常
cdl.countDown();
}
}
)
);
try {
//阻塞主线程,直到线程池处理完毕或超时
cdl.await(5, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("END-execute-countDownLatch");
}
@Test
public void submit() {
System.out.println("BEGIN-submit-unfutureGet");
IntStream.range(0, 10).forEach(x ->
taskExecutor.submit(() -> {
//submit使用future进行处理,异常会存储在临时变量中,触发异常抛出需要调用future.get()
//这里没有进行future.get()调用,出现异常会存在临时变量中不会抛出而是被“吞掉”,好处是不影响并行的其他线程任务,不好是永远不知道是否异常
throw new RuntimeException("error");
}
)
);
System.out.println("END-submit-unfutureGet");
}
@Test
public void submit_futureGetException() {
System.out.println("BEGIN-submit-futureGet");
IntStream.range(0, 10).forEach(x -> {
Future future = taskExecutor.submit(() -> {
//submit使用future进行处理,异常会存储在临时变量中,触发异常抛出需要调用future.get()
throw new RuntimeException("error");
}
);
try {
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
);
System.out.println("END-submit-futureGet");
}
}