IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 「Java工具类」java线程池工具类,自定义线程池工具类 -> 正文阅读

[Java知识库]「Java工具类」java线程池工具类,自定义线程池工具类

介绍语

本博客主要是Java常用关键技术点,通用工具类的分享;以及springboot+springcloud+Mybatisplus+druid+mysql+redis+swagger+maven+docker等集成框架的技术分享;datax、kafka、flink等大数据处理框架的技术分享。文章会不断更新,欢迎码友关注点赞收藏转发!

关注多的话,后面会录制一些视频教程,图文和视频结合,比如:图书介绍网站系统、抢购系统、大数据中台系统等。技术才是程序猿的最爱,码友们冲啊

正文:

java核心之一就是线程,而用线程池执行线程是好的方式。下面是我封装的一个线程池工具类,简单实用。欢迎收藏备用!

  • 为什么需要一个线程池工具类?

答:整个项目,用到线程执行任务的地方很多,不可能哪里用到就在那里直接new一个线程执行,这样资源得不到重复利用,一旦线程过多就会导致内存不足。

  • 线程池的好处是什么?

使用线程池执行线程任务,当一个线程执行完成一个任务之后,线程资源回到线程池,资源得到重复利用。

  • 线程池为什么使用自定义方式?

阿里文档推荐使用自定义线程池,因为java自带线程池都会有可能造成内存不足的问题。自定义线程池,根据服务器配置定制线程池核心线程、最大线程等,是最好的方式。

  • 我封装的线程池工具类有什么好处?

使用线程安全的方式定义,整个项目不会重复创建线程池。线程池根据服务器cpu核数创建合适的核心线程数和最大线程数,达到不少创建不多创建刚刚好的配置。使用静态方法调用,随处可用,零难度上手。可以执行无返回值线程任务,可以执行有返回值的线程任务。

工具类

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

import java.util.concurrent.*;

/**
 * 自定义线程创建工具类,创建线程池后不需要关闭
 *
 * @author liangxn
 */
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;
    }
}

例子1:

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

例子2:

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

例子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("我在这儿等着你回来等你回来");
??
?// 控制台打印:
?21:08:08.494 [main] INFO  - 任务0
?............
?21:08:08.540 [main] INFO  - 任务5
?21:08:08.541 [main] INFO  - 任务6
?21:08:08.540 [myPool-4] INFO  - 干活好累
?21:08:08.540 [myPool-1] INFO  - 干活好累
?21:08:08.540 [myPool-3] INFO  - 干活好累
?............
?21:08:08.543 [main] INFO  - 任务21
?21:08:08.548 [main] INFO  - 任务22
?21:08:08.548 [main] INFO  - 任务23
?21:08:08.548 [myPool-21] INFO  - 干活好累
?21:08:08.549 [main] INFO  - 任务24
?21:08:08.549 [myPool-22] INFO  - 干活好累
?21:08:08.549 [main] INFO  - 任务25
?21:08:08.549 [myPool-23] INFO  - 干活好累
?21:08:08.549 [main] INFO  - 任务26
?............
?21:08:08.551 [myPool-1] INFO  - 干活好累
?21:08:08.551 [myPool-6] INFO  - 终于干完了
?21:08:08.551 [myPool-7] INFO  - 终于干完了
?21:08:08.551 [myPool-5] INFO  - 干活好累
?21:08:08.551 [main] INFO  - 任务35
?21:08:08.551 [main] INFO  - 任务36
?21:08:08.551 [main] INFO  - 任务37
?21:08:08.551 [main] INFO  - 任务38
?21:08:08.551 [main] INFO  - 任务39
?21:08:08.551 [main] INFO  - 我在这儿等着你回来等你回来
?21:08:08.551 [myPool-2] INFO  - 干活好累
?21:08:08.551 [myPool-3] INFO  - 干活好累
?21:08:08.551 [myPool-8] INFO  - 干活好累
?21:08:08.551 [myPool-6] INFO  - 干活好累
?21:08:08.551 [myPool-7] INFO  - 干活好累
?21:08:08.552 [myPool-13] INFO  - 终于干完了
?21:08:08.552 [myPool-12] INFO  - 终于干完了
?............
?    
?21:08:08.561 [myPool-7] INFO  - 终于干完了
?21:08:08.561 [myPool-3] INFO  - 终于干完了

例子4:

?// 测试10个线程使用工具类
?ExecutorService executorService = Executors.newFixedThreadPool(10);
?for (int i = 0; i < 10; i++) {
?    executorService.submit(new Runnable() {
?        @Override
?        public void run() {
?            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("不用等他,我们先干");

?// 控制台打印:
?21:11:49.946 [main] INFO  - 不用等他,我们先干
?21:11:49.991 [myPool-4] INFO  - [pool-2-thread-7],干活好累
?21:11:49.991 [myPool-3] INFO  - [pool-2-thread-2],干活好累
?21:11:49.991 [myPool-5] INFO  - [pool-2-thread-5],干活好累
?21:11:49.991 [myPool-8] INFO  - [pool-2-thread-6],干活好累
?21:11:49.991 [myPool-1] INFO  - [pool-2-thread-3],干活好累
?21:11:49.991 [myPool-2] INFO  - [pool-2-thread-9],干活好累
?21:11:49.991 [myPool-9] INFO  - [pool-2-thread-10],干活好累
?21:11:49.991 [myPool-7] INFO  - [pool-2-thread-1],干活好累
?21:11:49.991 [myPool-6] INFO  - [pool-2-thread-4],干活好累
?21:11:49.991 [myPool-0] INFO  - [pool-2-thread-8],干活好累
?21:11:50.091 [myPool-7] INFO  - [pool-2-thread-1],终于干完了
?21:11:50.091 [myPool-4] INFO  - [pool-2-thread-7],终于干完了
?21:11:50.091 [myPool-5] INFO  - [pool-2-thread-5],终于干完了
?21:11:50.091 [myPool-2] INFO  - [pool-2-thread-9],终于干完了
?21:11:50.091 [myPool-0] INFO  - [pool-2-thread-8],终于干完了
?21:11:50.091 [myPool-1] INFO  - [pool-2-thread-3],终于干完了
?21:11:50.091 [myPool-8] INFO  - [pool-2-thread-6],终于干完了
?21:11:50.091 [myPool-6] INFO  - [pool-2-thread-4],终于干完了
?21:11:50.091 [myPool-3] INFO  - [pool-2-thread-2],终于干完了
?21:11:50.091 [myPool-9] INFO  - [pool-2-thread-10],终于干完了
例子5:
?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("不用等他,我们先干");
??
?// 控制台打印:
?............
?21:13:25.083 [myPool-19] INFO  - 干活好累
?21:13:25.083 [myPool-8] INFO  - 干活好累
?21:13:25.083 [myPool-30] INFO  - 干活好累
?21:13:25.085 [main] WARN  - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:1000
?21:13:25.085 [main] WARN  - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:1000
?21:13:25.085 [main] WARN  - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:1000
?21:13:25.085 [main] WARN  - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:1000
?21:13:25.106 [myPool-7] INFO  - 干活好累
?21:13:25.106 [myPool-11] INFO  - 干活好累
?21:13:25.106 [main] WARN  - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:1000
?21:13:25.106 [myPool-6] INFO  - 干活好累
?21:13:25.106 [myPool-4] INFO  - 干活好累
?21:13:25.106 [main] WARN  - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:1000
?21:13:25.106 [main] WARN  - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:1000
?............

鄙人编码十年多,在项目中也积累了一些工具类,很多工具类在每个项目都有在用,很实用。大部分是鄙人封装的,有些工具类是同事封装的,有些工具类已经不记得是ctrl+c的还是自己封装的了,现在有空就会总结项目中大部分的工具类,分享给各位码友。如果文章中涉及的代码有侵权行为请通知鄙人处理。

计划是先把工具类整理出来,正所谓工欲善其事,必先利其器。项目中不管是普通单体项目还是多模块maven项目或是分布式微服务,一部分功能模块都是可以重用的,工具类模块就是其中之一。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-29 12:51:50  更:2021-10-29 12:53:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:45:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码