【线程池工具类】打卡学习Java线程池(案例详解)

简介: 本期给大家分享线程池在Java项目中的真实案例,欢迎打卡!
【辰兮要努力】:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行!

博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端、后台、数据库、项目案例等相关知识点总结,感谢你的阅读和关注,希望我的博客能帮助到更多的人,分享获取新知,大家一起进步!

吾等采石之人,应怀大教堂之心,愿大家奔赴在各自的热爱里…

@[toc]


一、初识线程池

线程池入门参考:Java工作一年了,不会还不懂Java线程池的使用吧?(代码详解)
请添加图片描述
线程池优点

1、降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

2、提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

3、提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源。

在这里插入图片描述
线程池创建线程的流程和执行任务的流程我们一定要搞懂


二、进阶线程池

初学者是否有个这样的疑惑,实际项目中我们到底如何写线程池帮助我们创建线程执行任务?

请添加图片描述

线程池工具类在项目中的创建有很多种写法,如下分享一种案例写法,欢迎实践

请添加图片描述

分享一下线程池的工具类

import org.apache.log4j.Logger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;


/**
 * @program: ExecutorConfig
 * @description: 线程池相关帮助类
 * @author: 辰兮要努力
 * @create: 2021-09-25 10:23
 */
public class ExecutorConfig {

    /**
     * 记录对应的日志
     */
    private static Logger logger = Logger.getLogger(ExecutorConfig.class);

    private static ThreadPoolTaskExecutor thPoolInstance = null;

    /**
     * 线程池
     *
     * @return ThreadPoolTaskExecutor
     * @author 辰兮要努力
     * @date 2021-9-25 10:58:57
     */
    public static ThreadPoolTaskExecutor getThreadPoolInstance() {
        if (thPoolInstance != null) {
            return thPoolInstance;
        }

        synchronized (ExecutorConfig.class) {
            if (thPoolInstance == null) {
                try {
                    // 获取统一线程池
                    thPoolInstance = ApplicationContextHolder.getBean(ThreadPoolTaskExecutor.class);

                    if (thPoolInstance == null) {
                        // 如果统一线程池还是为空,将启动本地创建线程,进行保护。
                        thPoolInstance = getThPoolInstance();
                    }
                } catch (Exception e) {
                    logger.error("getThreadPoolInstance -> create thread pool error", e);
                } finally {
                    // 如果统一线程池还是为空,将启动本地创建线程,进行保护。
                    if (thPoolInstance == null) {
                        thPoolInstance = getThPoolInstance();
                    }
                }
            }
        }

        return thPoolInstance;
    }

    /**
     * 获取本地线程池
     *
     * @return ThreadPoolTaskExecutor
     * @author 辰兮要努力
     * @date 2021-9-25 10:58:53
     */
    private static ThreadPoolTaskExecutor getThPoolInstance() {
        /**
         * 如果对应的线程池不为空则直接返回,如果为空
         */
        if (thPoolInstance != null) {
            return thPoolInstance;
        }

        try {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            // 核心线程数10:线程池创建时候初始化的线程数
            executor.setCorePoolSize(10);
            // 最大线程数15:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
            executor.setMaxPoolSize(15);
            // 缓冲队列25:用来缓冲执行任务的队列
            executor.setQueueCapacity(25);
            // 允许线程的空闲时间200秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
            executor.setKeepAliveSeconds(200);
            // 线程池名的前缀:设置好了之后可以方便定位处理任务所在的线程池
            executor.setThreadNamePrefix("chenXI-");
            /**
             * 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略, 当线程池没有处理能力的时候,
             * 该策略会直接在 execute 方法的调用线程中运行被拒绝的任务; 如果执行程序已关闭,则会丢弃该任务
             */
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            // 设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
            executor.setWaitForTasksToCompleteOnShutdown(true);
            // 设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
            executor.setAwaitTerminationSeconds(60 * 2);
            executor.initialize();
            thPoolInstance = executor;
        } catch (Exception e) {
            logger.error("getThPoolInstance-> create thread pool error", e);
        }

        return thPoolInstance;
    }
}

在spring环境中获取非spring容器管理的bean

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * @program: ApplicationContextHolder
 * @description: 在spring环境中获取非spring容器管理的bean
 * @author: 辰兮要努力
 * @create: 2021-9-25 13:30:02
 */
public class ApplicationContextHolder implements ApplicationContextAware {


    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        applicationContext = ctx;
    }


    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }


    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }


    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        return (T) applicationContext.getBean(name);
    }

}

创建一个demo模拟一下一个接口处理多层业务

/**
 * @program:  ThreadPoolDemo
 * @description: 模拟业务场景:相关使用案例
 * @author: 辰兮要努力
 * @create: 2021-09-25 10:43
 */
public class ThreadPoolDemo {

    public static void main(String[] args) {
        /**
         * 在一个业务逻辑层面模拟处理三个业务事情
         * 如下业务1,2
         */
        long startTime1 = System.currentTimeMillis();
        //业务1:处理一下相关数据,同时计算出线程的执行时间
        handleNum();
        System.out.println("任务1执行完---------------");

        //业务2:用线程池创建一个线程帮助我们处理相关业务,同时计算出线程的执行时间
        ExecutorConfig.getThreadPoolInstance().execute(new Runnable() {
            @Override
            public void run() {
                /**
                 * 模拟一下新的业务逻辑
                 */
                handleNum();
                // TimeUnit.MILLISECONDS.sleep((int)(Math.random() * 1000));
                // 1000毫秒以内的随机数,模拟业务逻辑处理
                System.out.println("任务2执行完---------------");

            }
        });

        //业务:计算一下当前主线程的执行时间
        long lastTime1 = System.currentTimeMillis();
        System.out.println("主线程执行完-执行时间:"+ (lastTime1 - startTime1));
        
    }

    //创建一个方法模拟正常的业务逻辑,花费一定的时间
    public static void handleNum(){
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            i  = i ++;
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long lastTime = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName()+"线程执行时间:"+ (lastTime - startTime));
    }
}

程序分析:程序在主线程中正常执行,我们利用线程池创建出了一个单独的线程帮助我们处理业务二

输出结果

main线程执行时间:3682
任务1执行完---------------
主线程执行完-执行时间:4034
chenXI-1线程执行时间:3353
任务2执行完---------------

我们可以将上述逻辑修改为传统的串行的执行方式,我们发现程序的运行时间和响应时间明显加长!


为什么我们会使用多线程呢?
请添加图片描述

保证应用程序的响应性能,即良好的用户体验。同时可以提高CPU的利用率。

如上当业务逻辑复杂且响应时间慢的情况下,我们可以考虑利用线程池开启线程帮助我们处理相关业务逻辑。(异步处理)

本期讲解到此结束,如上案例均可以在自己电脑实践


非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤️ 分享👥 留言💬thanks!!!

愿你们奔赴在自己的热爱里!

目录
相关文章
|
6天前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
6天前
|
存储 监控 安全
一天十道Java面试题----第三天(对线程安全的理解------>线程池中阻塞队列的作用)
这篇文章是Java面试第三天的笔记,讨论了线程安全、Thread与Runnable的区别、守护线程、ThreadLocal原理及内存泄漏问题、并发并行串行的概念、并发三大特性、线程池的使用原因和解释、线程池处理流程,以及线程池中阻塞队列的作用和设计考虑。
|
1天前
|
缓存 Java
异步&线程池 线程池的七大参数 初始化线程的4种方式 【上篇】
这篇文章详细介绍了Java中线程的四种初始化方式,包括继承Thread类、实现Runnable接口、实现Callable接口与FutureTask结合使用,以及使用线程池。同时,还深入探讨了线程池的七大参数及其作用,解释了线程池的运行流程,并列举了四种常见的线程池类型。最后,阐述了在开发中使用线程池的原因,如降低资源消耗、提高响应速度和增强线程的可管理性。
异步&线程池 线程池的七大参数 初始化线程的4种方式 【上篇】
|
1天前
|
人工智能 Java 定位技术
人工智能ChatGPT 体验案例:使用ChatGPT实现java扫雷小游戏
这篇文章通过一个使用ChatGPT实现的Java扫雷小游戏案例,展示了ChatGPT在编程领域的应用能力。文章中包含了扫雷游戏的Java代码实现,代码中初始化了雷区地图,随机放置雷,计算每个格子周围雷的数量,并提供了一个简单的文本界面与用户交互进行游戏。游戏通过控制台输入接受玩家的指令,并给出相应的反馈。
人工智能ChatGPT 体验案例:使用ChatGPT实现java扫雷小游戏
|
4天前
|
前端开发 Java 编译器
【前端学java】如何从前端视角快速学习Maven
【8月更文挑战第12天】如何从前端视角快速学习Maven
12 2
【前端学java】如何从前端视角快速学习Maven
|
6天前
|
缓存 前端开发 Java
【前端学java】java基础巩固复习巩固语法练习-工具类的封装(14)
【8月更文挑战第10天】java基础巩固,工具类的封装
11 1
【前端学java】java基础巩固复习巩固语法练习-工具类的封装(14)
|
1天前
|
设计模式 Java
常用设计模式介绍~~~ Java实现 【概念+案例+代码】
文章提供了一份常用设计模式的全面介绍,包括创建型模式、结构型模式和行为型模式。每种设计模式都有详细的概念讲解、案例说明、代码实例以及运行截图。作者通过这些模式的介绍,旨在帮助读者更好地理解源码、编写更优雅的代码,并进行系统重构。同时,文章还提供了GitHub上的源码地址,方便读者直接访问和学习。
常用设计模式介绍~~~ Java实现 【概念+案例+代码】
|
7天前
|
缓存 监控 Java
Java性能优化:从单线程执行到线程池管理的进阶实践
在Java开发中,随着应用规模的不断扩大和用户量的持续增长,性能优化成为了一个不可忽视的重要课题。特别是在处理大量并发请求或执行耗时任务时,单线程执行模式往往难以满足需求,这时线程池的概念便应运而生。本文将从应用场景举例出发,探讨Java线程池的使用,并通过具体案例和核心代码展示其在实际问题解决中的强大作用。
22 1
|
8天前
|
Java
Java线程池核心数为0时,线程池如何执行?
【8月更文挑战第11天】Java线程池核心数为0时,线程池如何执行?
21 1
|
5天前
|
Java UED
基于SpringBoot自定义线程池实现多线程执行方法,以及多线程之间的协调和同步
这篇文章介绍了在SpringBoot项目中如何自定义线程池来实现多线程执行方法,并探讨了多线程之间的协调和同步问题,提供了相关的示例代码。
32 0