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

每篇一句

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

说在前面

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

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

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

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

实例模拟

1 importjava.util.concurrent.ExecutorService;2 importjava.util.concurrent.Executors;3

4 public classTestThread {5

6 public static voidmain(String[] args) {7 while (true) {8 try{9 ExecutorService service = Executors.newFixedThreadPool(1);10 service.submit(newRunnable() {11 public voidrun() {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秒就增长一个。

c4c257e04e8048b3fa5fcc7fd42af5ad.png

加了shutdown代码后

1 importjava.util.concurrent.ExecutorService;2 importjava.util.concurrent.Executors;3

4 public classTestThread {5

6 public static voidmain(String[] args) {7 while (true) {8 ExecutorService service = Executors.newFixedThreadPool(1);9 try{10 service.submit(newRunnable() {11 public voidrun() {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 }

就一直很平稳

151fddcc0e85308f42c8df4089f097db.png

再看个例子

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

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值