学习笔记:线程池执行抛出异常处理

1.使用线程池抛出异常处理:

<dependency>
    <groupId>com.google.guavagroupId>
    <artifactId>guavaartifactId>
    <version>31.1-jreversion>
dependency>
package com.tomdd.wechatarticle;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

/**
 * 

线程池中抛出异常测试

* 线程池中线程频繁出现未捕获异常 * 那线程的复用率就大大降低了,需要不断地创建新线程。 * * @author zx * @date 2022年10月17日 11:20 */
public class ThreadExecutorTest { /** * ·corePool:核心线程池的大小。 * ·maximumPool:最大线程池的大小。 * ·BlockingQueue:用来暂时保存任务的工作队列。 * ·RejectedExecutionHandler:当ThreadPoolExecutor已经关闭或ThreadPoolExecutor已经饱和时(达到了最大线程池大小且工作队列已满),execute()方法将要调用的Handler。 */ //private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, // new ArrayBlockingQueue<>(200), new NameTreadFactory(), new MyIgnorePolicy()); //new ThreadFactoryBuilder() guava 工具类提供的。 //private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, // new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); //要捕获那些没被业务代码捕获的异常,可以设置Thread类的uncaughtExceptionHandler属性。 // 这时使用ThreadFactoryBuilder会比较方便,ThreadFactoryBuilder是guava提供的ThreadFactory生成器。 private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d") .setUncaughtExceptionHandler((t, e) -> System.out.println(t.getName() + "发生异常" + e.getCause())) .build()); /** * 线程池中的线程执行任务抛出异常没有被捕获 * 在不断地创建新线程 */ @Test public void test01() { IntStream.rangeClosed(1, 5).forEach(i -> { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } threadPoolExecutor.execute(() -> { int j = 1 / 0; }); }); } /** * 线程池中执行任务的线程如果抛出异常没有被捕获 * 设置Thread类的uncaughtExceptionHandler属性,线程池中原有的线程没有复用 * 通过UncaughtExceptionHandler的设置,只是做了一层异常的保底处理。 */ @Test public void test02() { IntStream.rangeClosed(1, 5).forEach(i -> { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } threadPoolExecutor.execute(() -> { System.out.println("线程" + Thread.currentThread().getName() + "执行"); int j = 1 / 0; }); }); } /** * 线程池中执行任务的线程如果抛出异常没有被捕获 * 设置Thread类的uncaughtExceptionHandler属性,并没有实现复用效果 *

* 把excute改成submit试试: * 通过submit提交线程可以屏蔽线程中产生的异常,达到线程复用。当get()执行结果时异常才会抛出 * 通过submit提交的线程,当发生异常时,会将异常保存,待future.get();时才会抛出 * * 总结: * 1、线程池中线程中异常尽量手动捕获 * * 2、通过设置ThreadFactory的UncaughtExceptionHandler可以对未捕获的异常做保底处理,通过execute提交任务,线程依然会中断,而通过submit提交任务,可以获取线程执行结果,线程异常会在get执行结果时抛出。 */ @Test public void test03() { IntStream.rangeClosed(1, 5).forEach(i -> { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } Future<?> future = threadPoolExecutor.submit(() -> { System.out.println("线程" + Thread.currentThread().getName() + "执行"); int j = 1 / 0; }); try { future.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }); } /** * 线程池中的线程执行任务抛出异常被捕获 * 线程池中的额线程可以被重复使用 */ @Test public void test() { IntStream.rangeClosed(1, 5).forEach(i -> { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } threadPoolExecutor.execute(() -> { try { int j = 1 / 0; } catch (Exception e) { System.out.println(Thread.currentThread().getName() + " " + e.getMessage()); } }); }); } //设置线程名称 static class NameTreadFactory implements ThreadFactory { private final AtomicInteger mThreadNum = new AtomicInteger(1); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement()); System.out.println(t.getName() + " has been created"); return t; } } //拒绝策略: 当ThreadPoolExecutor已经关闭或ThreadPoolExecutor已经饱和时(达到了最大线程池大小且工作队列已满) static class MyIgnorePolicy implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { doLog(r, e); } private void doLog(Runnable r, ThreadPoolExecutor e) { System.err.println(r.toString() + " rejected"); System.out.println("completedTaskCount: " + e.getCompletedTaskCount()); } } }

2.总结:

  1. 线程池中线程中异常尽量手动捕获
  2. 通过设置ThreadFactoryUncaughtExceptionHandler可以对未捕获的异常做保底处理,通过execute提交任务,线程依然会中断,而通过submit提交任务,可以获取线程执行结果,线程异常会在get执行结果时抛出

你可能感兴趣的:(Springboot,java)