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


    每篇一句

    你如果不是富二代,你要努力让你的儿子成为富二代

    说在前面

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

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

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

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

    实例模拟

     1 import java.util.concurrent.ExecutorService;
     2 import java.util.concurrent.Executors;
     3  
     4 public class TestThread {
     5  
     6     public static void main(String[] args) {
     7         while (true) {
     8             try {
     9                 ExecutorService service = Executors.newFixedThreadPool(1);
    10                 service.submit(new Runnable() {
    11                     public void run() {
    12                         try {
    13                             Thread.sleep(2000); ////模拟处理业务
    14                         } catch (InterruptedException e) {
    15                         }
    16                     }
    17                 });
    18                 service = null;
    19             } catch (Exception e) {
    20             }
    21             try {
    22                 Thread.sleep(2000); 
    23             } catch (InterruptedException e) {
    24             }
    25         }
    26     }
    27  
    28 }

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

     加了shutdown代码后

     1 import java.util.concurrent.ExecutorService;
     2 import java.util.concurrent.Executors;
     3  
     4 public class TestThread {
     5  
     6     public static void main(String[] args) {
     7         while (true) {
     8             ExecutorService service = Executors.newFixedThreadPool(1);
     9             try {
    10                 service.submit(new Runnable() {
    11                     public void run() {
    12                         try {
    13                             Thread.sleep(2000);
    14                         } catch (InterruptedException e) {
    15                         }
    16                     }
    17                 });
    18             } catch (Exception e) {
    19             }finally{
    20                 service.shutdown();
    21             }
    22             try {
    23                 Thread.sleep(2000);
    24             } catch (InterruptedException e) {
    25             }
    26         }
    27     }
    28 }

    就一直很平稳

     再看个例子

    public static void main(String[] args) throws Exception {        //用于获取到本java进程,进而获取总线程数
        RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
        String jvmName = runtimeBean.getName();
        System.out.println("JVM Name = " + jvmName);
        long pid = Long.valueOf(jvmName.split("@")[0]);
        System.out.println("JVM PID  = " + pid);
        ThreadMXBean bean = ManagementFactory.getThreadMXBean();
        int n = 1000;
        for (int i = 0; i < n; i++) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 1000, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
            for (int j = 0; j < 5; j++) {
                executor.execute(() -> {
                    System.out.println("当前线程总数为:" + bean.getThreadCount());
                });
            }
             // executor.shutdown();
        }
        Thread.sleep(10000);
        System.out.println("线程总数为 = " + bean.getThreadCount());
    }

    这里ThreadPoolExecutor作为局部变量,若你不手动关闭:最后一句输出为

    1 线程总数为 = 5006

    也就是说:线程全部泄漏(一个线程都没有死,没有被回收),白白的浪费了内存。这个在内存吃紧的时候容易造成死机。
    那么加上executor.shutdown()这句,手动去给它关闭呢?最终打印:

    1 线程总数为 = 6

    可见,效果是非常好的。因此:局部线程池,请务必务必要手动关闭

    注意:还有个区别是若你没有shutdonw,那么最终主线程是不会终止的。而如果你shutdown了,主线程跑完也就终止了。

    最后说明

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

    转载于:https://blog.csdn.net/f641385712/article/details/82021919

  • 相关阅读:
    【LeetCode】456. 132 Pattern
    【Python&Sort】QuickSort
    Python虚拟环境的配置
    【LeetCode】459. Repeated Substring Pattern
    【LeetCode】462. Minimum Moves to Equal Array Elements II
    【LeetCode】20. Valid Parentheses
    radio 获取选中值
    页面加载时自动执行(加载)js的几种方法
    加一个字段: updateTime 更新时间
    多用户同时处理同一条数据解决办法
  • 原文地址:https://www.cnblogs.com/it-deepinmind/p/13072054.html
Copyright © 2020-2023  润新知