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

版权声明: https://blog.csdn.net/f641385712/article/details/82021919

推荐阅读

【小家java】java5新特性(简述十大新特性) 重要一跃
【小家java】java6新特性(简述十大新特性) 鸡肋升级
【小家java】java7新特性(简述八大新特性) 不温不火
【小家java】java8新特性(简述十大新特性) 饱受赞誉
【小家java】java9新特性(简述十大新特性) 褒贬不一
【小家java】java10新特性(简述十大新特性) 小步迭代


说在前面

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

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

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

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了。但一般都是整数倍

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

猜你喜欢

转载自blog.csdn.net/f641385712/article/details/82021919