专栏首页BAT的乌托邦【小家Java】自定义的线程池需要关闭吗?(局部变量Executors线程池一定要手动关闭)

【小家Java】自定义的线程池需要关闭吗?(局部变量Executors线程池一定要手动关闭)

说在前面

线程池关闭的意义不仅仅在于结束线程执行,避免内存溢出,因为大多使用的场景并非上述示例那样 朝生夕死。线程池一般是持续工作的全局场景,如数据库连接池。

我之前看到很多同事写代码,为了提高效率,采用多线程去优化。由为了提高多线程的性能,用到了线程池。

表面上看起来很高大上了,但其实上发现很多人用到了局部变量的线程池,然后使用过后并没有回收,导致了线程泄漏甚至内存溢出。

Executors作为局部变量时,创建了线程,一定要记得调用executor.shutdown();来关闭线程池,如果不关闭,会有线程泄漏问题。

实例模拟

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
public class TestThread {
 
    public static void main(String[] args) {
        while (true) {
            try {
                ExecutorService service = Executors.newFixedThreadPool(1);
                service.submit(new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep(2000); ////模拟处理业务
                        } catch (InterruptedException e) {
                        }
                    }
                });
                service = null;
            } catch (Exception e) {
            }
            try {
                Thread.sleep(2000); 
            } catch (InterruptedException e) {
            }
        }
    }
 
}

运行后,查看jvm,会发现线程每2秒就增长一个。

加了shutdown代码后

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
public class TestThread {
 
    public static void main(String[] args) {
        while (true) {
            ExecutorService service = Executors.newFixedThreadPool(1);
            try {
                service.submit(new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                        }
                    }
                });
            } catch (Exception e) {
            }finally{
                service.shutdown();
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
        }
    }
} 

就一直很平稳

最后说明

此处用的newFixedThreadPool(1)来模拟业务创建,但是勿喷。实际情况中一般不会创建只有一个线程的线程池,这里只是表达一个意思即可。

希望大家能够举一反三。

线程池设置多大合适呢

虽然线程池大小的设置受到很多因素影响,但是这里给出一个参考公式:

最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

比如平均每个线程CPU运行时间为0.5s,而线程等待时间(非CPU运行时间,比如IO)为1.5s,CPU核心数为8,那么根据上面这个公式估算得到:((0.5+1.5)/0.5)*8=32。这个公式进一步转化为:

最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目

线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。

所以并不是单纯的只是配一个CUP核心数就ok了。但一般都是整数倍

若对于线程池的关闭有更多疑问,推荐博文:线程池的优雅关闭实践

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ThreadLocal垮线程池传递数据解决方案:TransmittableThreadLocal【享学Java】

    在 上篇文章 了解到了,ThreadLocal它并不能解决线程安全问题,它旨在用于传递数据。但是它能成功传递数据比如有个大前提:放数据和取数据的操作必须是处于相...

    YourBatman
  • 【小家java】Java中主线程(父线程)与子线程的通信和联系

    通俗的讲, 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位(比如QQ是个进程、微信是个进程)

    YourBatman
  • 【小家java】Java里的进程、线程、协程 、Thread、守护线程、join线程的总结

    说到线程,很多人最直观的感受就是多线程。本章不讨论高并发、多线程之类的。返璞归真,咱们来讨论讨论线程这个东西到底是什么东西,着眼于线程本身,我们怎么玩? 为了...

    YourBatman
  • Java多线程和线程池

    在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际...

    Java编程指南
  • 线程的基本状态

    1、新建状态(New):新创建了一个线程对象。 2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可...

    shimeath
  • 【Java】基础30:线程与进程,并行与并发

    其实很好理解,第一个while循环是死循环,如果我们不强行将程序停止的话,它是会无止境的永远运行下去的,那么第二个死循环语句根本就没法运行到。

    刘小爱
  • 用java写一个死锁

    多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。

    yaphetsfang
  • 猿思考系列2——一文搞懂同步并发套路

    看完上一个章节,相信你已经充分的理解java代码的执行套路了,猿人工厂君也知道,内容对于新手而言,理解起来还是很吃力的,不过上一章节涉及编译原理、类加载机制和一...

    山旮旯的胖子
  • 彻底搞懂 Java 线程池,干啥都不再发憷

    作为 Java 程序员,无论是技术面试、项目研发或者是学习框架源码,不彻底掌握 Java 多线程的知识,做不到心中有数,干啥都没底气,尤其是技术深究时往往略显发...

    一猿小讲
  • 如何暂停一个正在运行的线程?

    停止线程是在多线程开发中很重要的技术点,比如在多线程持续处理业务代码时,由于处理逻辑中有第三方接口异常,我们就假设发送短信接口挂了吧,那么此时多线程调用短信接口...

    niceyoo

扫码关注云+社区

领取腾讯云代金券