首先看一个简单的例子:代码可能会抛出空指针异常,但这个异常就会被吞掉。
要优雅解决问题,可以为线程池设置一个全局的异常处理器,使用自定义
的线程工厂
来设置!
java
public class CustomThreadFactory implements ThreadFactory {
private final ThreadFactory defaultFactory = Executors.defaultThreadFactory();
@Override
public Thread newThread(Runnable r) {
Thread thread = defaultFactory.newThread(r);
// 设置全局异常处理器
thread.setUncaughtExceptionHandler((t, e) -> {
System.err.println("Thread " + t.getName() + " threw exception: " + e.getMessage());
});
return thread;
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2, new CustomThreadFactory());
// 提交任务到线程池
executorService.execute(() -> {
throw new NullPointerException("Test Exception");
});
// 关闭线程池
executorService.shutdown();
}
}
拒绝策略设置错误导致接口超时!
如果没有正确设置拒绝策略,可能会导致接口超时或服务中断。
java
public class RejectionPolicyExample {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(
1, // 核心线程数
1, // 最大线程数
0L, // 空闲线程存活时间
TimeUnit.MILLISECONDS, // 存活时间单位
new LinkedBlockingQueue<>(1), // 任务队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.AbortPolicy() // 默认拒绝策略
);
// 提交三个任务到线程池,第三个任务将被拒绝
for (int i = 0; i < 3; i++) {
executorService.execute(() -> {
try {
Thread.sleep(1000); // 模拟任务执行
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " executed task");
});
}
// 关闭线程池
executorService.shutdown();
}
}
合适的拒绝策略如CallerRunsPolicy
可以使任务在调用者线程中执行,从而避免任务丢失。
java
public class CallerRunsPolicyExample {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(
1, // 核心线程数
1, // 最大线程数
0L, // 空闲线程存活时间
TimeUnit.MILLISECONDS, // 存活时间单位
new LinkedBlockingQueue<>(1), // 任务队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 调用者运行策略
);
// 提交三个任务到线程池,第三个任务将在调用者线程中执行
for (int i = 0; i < 3; i++) {
executorService.execute(() -> {
try {
Thread.sleep(1000); // 模拟任务执行
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " executed task");
});
}
// 关闭线程池
executorService.shutdown();
}
}
重复创建线程池导致内存溢出
重复创建线程池会导致系统资源浪费,甚至引发内存溢出。
java
public class DuplicateThreadPoolExample {
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 提交任务到线程池
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName() + " executed task");
});
// 关闭线程池
executorService.shutdown();
}
}
}
那当然我们整个应用中只使用一个线程池实例。
java
public class SingletonThreadPoolExample {
// 单例线程池
private static final ExecutorService executorService = Executors.newFixedThreadPool(10);
public static ExecutorService getExecutorService() {
return executorService;
}
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
// 使用单例线程池提交任务
getExecutorService().execute(() -> {
System.out.println(Thread.currentThread().getName() + " executed task");
});
}
// 关闭线程池
getExecutorService().shutdown();
}
}
共用线程池执行不同任务
在同一个线程池中执行不同性质的任务,可能会导致任务相互影响,进而降低系统效率。例如,CPU密集型
和IO密集型
任务混用同一线程池,效率会大打折扣。
java
public class MixedTasksExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 提交CPU密集型任务
executorService.execute(() -> {
for (int i = 0; i < 1000000; i++) {} // 模拟CPU密集型任务
System.out.println(Thread.currentThread().getName() + " executed CPU-intensive task");
});
// 提交IO密集型任务
executorService.execute(() -> {
try {
Thread.sleep(2000); // 模拟IO密集型任务
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " executed IO-intensive task");
});
// 关闭线程池
executorService.shutdown();
}
}
解决方案:
为不同任务分配独立
的线程池,确保任务执行的高效性。
java
public class SeparateTasksExample {
// CPU密集型任务的线程池
private static final ExecutorService cpuIntensivePool = Executors.newFixedThreadPool(5);
// IO密集型任务的线程池
private static final ExecutorService ioIntensivePool = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
// 提交CPU密集型任务
cpuIntensivePool.execute(() -> {
for (int i = 0; i < 1000000; i++) {} // 模拟CPU密集型任务
System.out.println(Thread.currentThread().getName() + " executed CPU-intensive task");
});
// 提交IO密集型任务
ioIntensivePool.execute(() -> {
try {
Thread.sleep(2000); // 模拟IO密集型任务
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " executed IO-intensive task");
});
// 关闭线程池
cpuIntensivePool.shutdown();
ioIntensivePool.shutdown();
}
}
ThreadLocal与线程池的冲突
因为线程池中的线程是复用
的,ThreadLocal中的变量可能会被其他任务不小心修改
或未及时清理
。
java
public class ThreadLocalIssueExample {
private static final ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 提交任务到线程池
for (int i = 0; i < 5; i++) {
executorService.execute(() -> {
int value = threadLocal.get();
System.out.println(Thread.currentThread().getName() + " initial value: " + value);
threadLocal.set(value + 1);
System.out.println(Thread.currentThread().getName() + " updated value: " + threadLocal.get());
});
}
// 关闭线程池
executorService.shutdown();
}
}
那当然在任务执行完毕后,及时清理
ThreadLocal变量
public class ThreadLocalSolutionExample {private static final ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);// 提交任务到线程池for (int i = 0; i < 5; i++) {executorService.execute(() -> {try {int value = threadLocal.get();System.out.println(Thread.currentThread().getName() + " initial value: " + value);threadLocal.set(value + 1);System.out.println(Thread.currentThread().getName() + " updated value: " + threadLocal.get());} finally {// 任务完成后清理ThreadLocal变量threadLocal.remove();}});}// 关闭线程池executorService.shutdown();}
}
最后说一句(求关注!别白嫖!)
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。
关注公众号:woniuxgg,在公众号中回复:笔记 就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!