【线程池工具类】打卡学习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!!!

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

目录
相关文章
|
3月前
|
存储 Oracle Java
java零基础学习者入门课程
本课程为Java零基础入门教程,涵盖环境搭建、变量、运算符、条件循环、数组及面向对象基础,每讲配示例代码与实践建议,助你循序渐进掌握核心知识,轻松迈入Java编程世界。
338 0
|
3月前
|
负载均衡 Java API
grpc-java 架构学习指南
本指南系统解析 grpc-java 架构,涵盖分层设计、核心流程与源码结构,结合实战路径与调试技巧,助你从入门到精通,掌握高性能 RPC 开发精髓。
356 8
|
3月前
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
243 1
|
4月前
|
Java
Java基础学习day08-作业
本作业涵盖Java中Lambda表达式的应用,包括Runnable与Comparator接口的简化实现、自定义函数式接口NumberProcessor进行加减乘及最大值操作,以及通过IntProcessor处理整数数组,实现遍历、平方和奇偶判断等功能,强化函数式编程实践。
89 5
|
4月前
|
Java API 容器
Java基础学习day08-2
本节讲解Java方法引用与常用API,包括静态、实例、特定类型方法及构造器引用的格式与使用场景,并结合代码示例深入解析。同时介绍String和ArrayList的核心方法及其实际应用。
169 1
|
4月前
|
Java 程序员
Java基础学习day08
本节讲解Java中的代码块(静态与实例)及其作用,深入介绍内部类(成员、静态、局部及匿名)的定义与使用,并引入函数式编程思想,重点阐述Lambda表达式及其在简化匿名内部类中的应用。
163 5
|
4月前
|
Java
Java基础学习day07-作业
本作业包含六个Java编程案例:1)动物类继承与多态;2)加油卡支付系统;3)员工管理类设计;4)学生信息统计接口;5)USB设备控制;6)家电智能控制。综合运用抽象类、接口、继承、多态等面向对象技术,强化Java基础编程能力。
196 3
|
4月前
|
Java
Java基础学习day06-作业
本内容为Java基础学习作业,涵盖两个案例:一是通过Card类及其子类GoldenCard、SilverCard实现加油卡系统,体现封装与继承;二是通过Shape类及子类Circle、Rectangle演示多态与方法重写,强化面向对象编程理解。
104 1
|
4月前
|
设计模式 存储 Java
Java基础学习day07
本节讲解Java中的final关键字、单例设计模式、枚举类、抽象类与接口。涵盖常量定义、单例写法(饿汉式/懒汉式)、枚举特点及应用场景,以及抽象类与接口的使用与区别,助力掌握核心面向对象编程思想。
154 1
|
4月前
|
Java
Java基础学习day05-作业
本文为Java基础学习第五天作业,通过五个案例练习类与对象的定义、构造方法、set/get方法及成员方法的应用。涵盖女友、学生、教师、手机和电影等类的设计与测试,强化面向对象编程基础。
96 2

热门文章

最新文章