文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

简单聊一聊Java线程池ThreadPoolExecutor

2024-04-02 19:55

关注

简介

ThreadPoolExecutor是一个实现ExecutorService接口的线程池,ExecutorService是主要用来处理多线程任务的一个接口,通常比较简单是用法是由Executors工厂类去创建。

线程池主要解决了两个不同的问题:

参数说明

ThreadPoolExecutor提供了几个核心参数,方便开发人员根据具体场景合理分配线程资源。

注:maximumPoolSize如果大于corePoolSize,则多出的部分线程数只有在阻塞队列workQueue占满时才会创建核心线程之外的线程去执行任务,如果我们设置的阻塞队列为无界队列(默认大小为Integer.MAX_VALUE),则队列永远无法占满,就不会去创建额外的线程进行工作,一般情况如果任务数足够,那么也是在队列大小还没达到Integer.MAX_VALUE时就已经出现内存溢出了。Executors线程池工厂中的newFixedThreadPool()、newSingleThreadExecutor()方法就是使用了无界队列LinkedBlockingQueue,防止内存溢出在日常开发过程中一般是不建议直接去使用Executors去创建线程池。

如何创建线程池

上面我们提到的可以使用Executors工厂直接创建线程池,但是Executors提供的创建线程池都是不可控的,我们还是得按自己的业务做好分析自定义一个线程池。

以下是线程池创建的一个案例:

@Slf4j
@Configuration
public class ThreadPoolConfig {

    @Value("${threadPool.corePoolSize:8}")
    private int corePoolSize;

    @Value("${threadPool.maximumPoolSize:16}")
    private int maximumPoolSize;

    @Value("${threadPool.keepAliveTime:60}")
    private int keepAliveTime;

    @Value("${threadPool.queueSize:99999}")
    private int queueSize;

    @Bean
    public ThreadPoolExecutor testExecutor() {
        LinkedBlockingQueue queue = new LinkedBlockingQueue(queueSize);
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, 
                TimeUnit.SECONDS, queue, getThreadFactory(), getRejectedExecutionHandler());
    }

    
    private ThreadFactory getThreadFactory() {
        return new ThreadFactory() {

            @Override
            public Thread newThread(Runnable r) {
                log.info("===> Create new thread ...");
                return new Thread(r);
            }
        };
    }

    
    private RejectedExecutionHandler getRejectedExecutionHandler() {
        return new RejectedExecutionHandler() {

            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                // 继续往队列里添加任务,这里只是一个案例,这种方式并不友好,会抛出队列已满的异常
                log.info("===> Handler runnable ......");
                executor.getQueue().add(r);
            }
        };
    }
}

application.properties配置文件

threadPool:
  corePoolSize: 8
  maximumPoolSize: 16
  keepAliveTime: 60
  # 为方便测试这里我们配置队列数小一点
  queueSize: 99

由以上的线程池配置,我们写一个demo测试一下:

截取部分运行日志:

注:可能有的同学会想线程池使用后需要销毁吗?在这里补充一下,如果我们是作为局部变量创建出来的线程池(如:在执行的方法内使用Executors.newFixedThreadPool(10)创建临时的线程池),这种情况我们用完就必须将它立即销毁,否则主线程就会一直处于运行状态。如果是全局配置的线程池,那么就是为整个系统中诸多业务提供使用的,这种就不需要对线程池做销毁,因为一旦销毁了其他的任务就无法继续使用该线程池执行任务。

拒绝策略

通常我们在配置好有限队列大小后,就会有可能出现队列占满的情况,这时候我们的拒绝策略就会起到作用,接下来我们就来分析一下RejectedExecutionHandler接口具体有哪一些实现方式:

private RejectedExecutionHandler getRejectedExecutionHandler() {
    return new RejectedExecutionHandler() {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            // 伪代码
            log.info("===> 可根据任务的重要性区分对待,将任务做转换入库延迟处理 ......");
        }
    };
}

总结

线程池是为了充分利用CPU资源,在合理分批使用的情况下能够极大的提高我们程序的性能,以上的参数配置仅作为参考,并没有一个标准的依据,只能在实际开发过程中开发人员自行多做一些测试来判断参数如何配置更加合理。

在拒绝策略配置方面,如果被拒绝的任务相对紧急且重要不可丢弃的情况下,此类任务可独立做一个线程池处理保证任务不丢失,程序只能慢慢优化变得越来越好,不可能有完美的程序即保证高性能又保证安全可靠。

到此这篇关于Java线程池ThreadPoolExecutor的文章就介绍到这了,更多相关Java线程池ThreadPoolExecutor内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯