原文代码抄的: 自己写了点代码权当自己留存
面试官:线程池执行过程中遇到异常会发生什么,怎样处理? - 知乎
一 线程池构造函数未使用setUncaughtExceptionHandler构造
package com.text;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.junit.Test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
/**
* 未设定 exceptionhandler
*/
public class TestUnCatchExceptionThreadPool {
private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 20,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), new ThreadFactoryBuilder().setNameFormat("current-thread-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy());
/**
* 未补货的异常: 线程被回收,抛出异常 线程对象重新new
* 输出结果如下: 抛出异常
* Exception in thread "current-thread-0" java.lang.ArithmeticException: / by zero
* at com.apple.allocation.TestThreadPool.lambda$test$0(TestThreadPool.java:37)
* at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
* at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
* at java.base/java.lang.Thread.run(Thread.java:833)
* Exception in thread "current-thread-1" java.lang.ArithmeticException: / by zero
...
* Exception in thread "current-thread-2" java.lang.ArithmeticException: / by zero
...
* Exception in thread "current-thread-3" java.lang.ArithmeticException: / by zero
...
* Exception in thread "current-thread-4" java.lang.ArithmeticException: / by zero
*/
@Test
public void executeOnUnCatchException() {
IntStream.range(0,5).forEach(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
threadPoolExecutor.execute(()->{
int a= 1 / 0;
});
});
}
/**
* 对线程执行的程序进行catch异常处理, 线程实现了复用,打印出了异常
* 输出结果:
current-thread-0 / by zero
current-thread-0 / by zero
current-thread-0 / by zero
current-thread-0 / by zero
current-thread-0 / by zero
*/
@Test
public void executeOnCatchException(){
IntStream.range(0,5).forEach(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException exception) {
throw new RuntimeException();
}
threadPoolExecutor.execute(()->{
try {
int a= 1 / 0;
} catch (Exception e) {
System.out.println(Thread.currentThread().getName()+" "+e.getMessage());
}
});
});
}
/**
* 线程submit: 线程实现了复用,未抛出异常
* 输出结果: 以下结果未简写. 只输出了 线程名报错异常没有任何输出
* current-thread-0
* current-thread-0
* current-thread-0
* current-thread-0
* current-thread-0
*/
@Test
public void test2() {
IntStream.range(0,5).forEach(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
threadPoolExecutor.submit(()->{
System.out.println(Thread.currentThread().getName());
int a= 1 / 0;
});
});
}
}
二 线程池构造函数使用setUncaughtExceptionHandler构造
package com.text;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.junit.Test;
import java.util.concurrent.*;
import java.util.stream.IntStream;
/**
* 设定 setUncaughtExceptionHandler
*/
/**
*
* 1、线程池中线程中异常尽量手动捕获
*
* 2、通过设置ThreadFactory的UncaughtExceptionHandler可以对未捕获的异常做保底处理,
* 通过execute提交任务,线程依然会中断,而通过submit提交任务,可以获取线程执行结果,线程异常会在get执行结果时抛出。
*/
public class TestCatchedExceptionThreadPool {
private ThreadPoolExecutor catchedExceptionthreadPoolExecutor = new ThreadPoolExecutor(1, 1, 20,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), new ThreadFactoryBuilder().setNameFormat("current-thread-%d").setUncaughtExceptionHandler(
(t, e) -> {
System.out.printf("%s ExceptionHandler 捕获了 %s%n", t.getName(), e.getMessage());
}
).build(),
new ThreadPoolExecutor.CallerRunsPolicy());
/**
* 未补货的异常: 线程被回收,未抛出异常 线程对象重新new
* 输出结果如下: 抛出异常
current-thread-0 ExceptionHandler 捕获了 / by zero
current-thread-1 ExceptionHandler 捕获了 / by zero
current-thread-2 ExceptionHandler 捕获了 / by zero
current-thread-3 ExceptionHandler 捕获了 / by zero
current-thread-4 ExceptionHandler 捕获了 / by zero
*/
@Test
public void executeOnUnCatchException() {
IntStream.range(0,5).forEach(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
catchedExceptionthreadPoolExecutor.execute(()->{
int a= 1 / 0;
});
});
}
/**
* 对线程执行的程序进行catch异常处理, 线程实现了复用,打印出了异常
* 输出结果: 内部catch程序打印的
current-thread-0 / by zero
current-thread-0 / by zero
current-thread-0 / by zero
current-thread-0 / by zero
current-thread-0 / by zero
*/
@Test
public void executeOnCatchException(){
IntStream.range(0,5).forEach(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException exception) {
throw new RuntimeException();
}
catchedExceptionthreadPoolExecutor.execute(()->{
try {
int a= 1 / 0;
} catch (Exception e) {
System.out.println(Thread.currentThread().getName()+" "+e.getMessage());
}
});
});
}
/**
* 线程submit: 线程实现了复用,未抛出异常
* 输出结果: 无任何输出,
*/
@Test
public void test2() {
IntStream.range(0,5).forEach(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
catchedExceptionthreadPoolExecutor.submit(()->{
int a= 1 / 0;
});
});
}
/**
* 通过submit提交线程可以屏蔽线程中产生的异常,达到线程复用。当get()执行结果时异常才会抛出。
*
* 原因是通过submit提交的线程,当发生异常时,会将异常保存,待future.get();时才会抛出。
*/
@Test
public void test3() {
IntStream.range(0,5).forEach(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Future<?> submit = catchedExceptionthreadPoolExecutor.submit(() -> {
int a = 1 / 0;
});
System.out.println("------");
try {
submit.get();
} catch (Exception e) {
System.out.println(Thread.currentThread().getName()+ e.getMessage());
}
});
}
}
三 总结
1 线程出现未捕获异常的时候执行不下去会被垃圾回收
2 线程池中 execute :
a)出现未捕获异常线程也会被回收无法实现复用
b) 程序内捕获 可以实现线程复用
c) 设置setUncaughtExceptionHandler 回线程也无法复用,只能保底
3 线程池中submit
a)出现未捕获异常可以实现复用, 但等到Future.get() 时才会抛出异常
b)其他与excute相同
刚看完一个月就忘了....再来看看...2023年10月13日