【Java 开发工具】Java 线程池工具类

403 阅读3分钟

美女背景图1.png

废话不多说系列,直接上源码,建议收藏订阅!

一、maven依赖

<!-- google Guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

二、完整源码

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * 自定义线程创建工具类,创建线程池后不需要关闭
 */
public class ThreadPoolUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolUtils.class);
    private static ThreadPoolExecutor threadPool = null;
    private static final String POOL_NAME = "myPool";
    // 等待队列长度
    private static final int BLOCKING_QUEUE_LENGTH = 1000;
    // 闲置线程存活时间
    private static final int KEEP_ALIVE_TIME = 60 * 1000;

    private ThreadPoolUtils() {
        throw new IllegalStateException("utility class");
    }


    /**
     * 无返回值直接执行
     *
     * @param runnable 需要运行的任务
     */
    public static void execute(Runnable runnable) {
        getThreadPool().execute(runnable);
    }

    /**
     * 有返回值执行
     * 主线程中使用Future.get()获取返回值时,会阻塞主线程,直到任务执行完毕
     *
     * @param callable 需要运行的任务
     */
    public static <T> Future<T> submit(Callable<T> callable) {
        return getThreadPool().submit(callable);
    }

    private static synchronized ThreadPoolExecutor getThreadPool() {
        if (threadPool == null) {
            // 获取处理器数量
            int cpuNum = Runtime.getRuntime().availableProcessors();
            // 根据cpu数量,计算出合理的线程并发数
            int maximumPoolSize = cpuNum * 2 + 1;
            // 核心线程数、最大线程数、闲置线程存活时间、时间单位、线程队列、线程工厂、当前线程数已经超过最大线程数时的异常处理策略
            threadPool = new ThreadPoolExecutor(maximumPoolSize - 1,
                    maximumPoolSize,
                    KEEP_ALIVE_TIME,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingDeque<>(BLOCKING_QUEUE_LENGTH),
                    new ThreadFactoryBuilder().setNameFormat(POOL_NAME + "-%d").build(),
                    new ThreadPoolExecutor.AbortPolicy() {
                        @Override
                        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                            LOGGER.warn("线程爆炸了,当前运行线程总数:{},活动线程数:{}。等待队列已满,等待运行任务数:{}",
                                    e.getPoolSize(),
                                    e.getActiveCount(),
                                    e.getQueue().size());
                        }
                    });

        }

        return threadPool;
    }

}

三、测试代码示例

public class Test {
    public static void main(String[] args) {
        test2();
    }

    private static void test1() {
        // 案例1:有返回值-超时(控制台打印日志:21:04:19.428 [main] INFO  - 我有返回值哦)
        Future<String> future = ThreadPoolUtils.submit(() -> "我有返回值哦");
        try {
            LOGGER.info(future.get());
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("任务超过指定时间未返回值,线程超时退出");
        }
    }

    private static void test2() {
        // 案例2:有返回值-超时(控制台打印日志:21:07:24.940 [main] ERROR - 任务超过指定时间未返回值,线程超时退出)
        Future<String> futureTimeout = ThreadPoolUtils.submit(() -> {
            Thread.sleep(99999999);
            return "我有返回值,但是超时了";
        });
        try {
            // 1.建议使用该方式执行任务,不会导致线程因为某些原因一直占用线程,从而导致未知问题
            // 2.注意使用局部try避免主线程异常,导致主线程无法继续执行
            LOGGER.info(futureTimeout.get(3, TimeUnit.SECONDS));
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("任务执行异常");
        } catch (TimeoutException e) {
            LOGGER.error("任务超过指定时间未返回值,线程超时退出");
        }
    }

    private static void test3() {
        // 案例3:
        int loop = 40;
        for (int i = 0; i < loop; i++) {
            LOGGER.info("任务{}", i);
            ThreadPoolUtils.execute(() -> {
                LOGGER.info("干活好累");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                LOGGER.info("终于干完了");
            });
        }
        LOGGER.info("我在这儿等着你回来等你回来");
    }

    private static void test4() {
        // 测试10个线程使用工具类
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.submit(() -> {
                final String name = Thread.currentThread().getName();
                ThreadPoolUtils.execute(() -> {
                    LOGGER.info("[{}],干活好累", name);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    LOGGER.info("[{}],终于干完了", name);
                });
            });
        }
        LOGGER.info("不用等他,我们先干");
    }

    private static void test5() {
        int loop = 2000;
        for (int i = 0; i < loop; i++) {
            ThreadPoolUtils.execute(() -> {
                LOGGER.info("干活好累");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                LOGGER.info("终于干完了");
            });
        }
        LOGGER.info("不用等他,我们先干");
    }
}

至此,致谢阅读!


美女背景图1.png