对于经常使用第三方框架进行web开发的程序员来说,Java线程池理所应当是非常智能的,线程的生命周期应该完全由Java本身控制,我们要做的就是添加任务和执行任务。但是,最近做文档批量上传同步时发现线程池中的所有任务执行完毕后,线程并没有停止,然后做了一个测试,发现确实如此:
 
问题及现象:
 
     public static void method1() {
          BlockingQueue queue = new LinkedBlockingQueue();
          ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 10, TimeUnit.SECONDS, queue);   
          for ( int i = 0; i < 20; i++) {
              executor.execute( new Runnable() {
                  public void run() {
                      try {
                          System. out.println( this.hashCode()/1000);
                            for ( int j = 0; j < 10; j++) {
                               System. out.println( this.hashCode() + ":" + j);
                               Thread.sleep(this.hashCode()%2);
                          } 
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System. out.println(String. format("thread %d finished", this.hashCode()));
                  }
              });
          }
      }
debug模式下,任务执行完后,显示的效果如下:
也就是说,任务已经执行完毕了,但是线程池中的线程并没有被回收。但是我在ThreadPoolExecutor的参数里面设置了超时时间的,好像没起作用,原因如下:
工作线程回收需要满足三个条件:

1)  参数allowCoreThreadTimeOut为true

2)  该线程在keepAliveTime时间内获取不到任务,即空闲这么长时间

3)  当前线程池大小 > 核心线程池大小corePoolSize。
 
解决一:
 
      public static void method1() {
          BlockingQueue queue = new LinkedBlockingQueue();
          ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.SECONDS, queue);  
          executor.allowCoreThreadTimeOut(true);
          for ( int i = 0; i < 20; i++) {
              executor.execute( new Runnable() {
                  public void run() {
                      try {
                           System. out.println( this.hashCode()/1000);
                              for ( int j = 0; j < 10; j++) {
                                System. out.println( this.hashCode() + ":" + j);
                                Thread. sleep(this.hashCode()%2);
                           } 
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System. out.println(String. format("thread %d finished", this.hashCode()));
                  }
              });
          }
      }
需要注意的是,allowCoreThreadTimeOut 的设置需要在任务执行之前,一般在new一个线程池后设置;在allowCoreThreadTimeOut设置为true时,ThreadPoolExecutor的keepAliveTime参数必须大于0。
 
 
解决二:
 
     public static void method1() {
          BlockingQueue queue = new LinkedBlockingQueue();
          ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.SECONDS, queue);
          for ( int i = 0; i < 20; i++) {
              executor.execute( new Runnable() {
                  public void run() {
                      try {
                          System. out.println( this.hashCode()/1000);
                            for ( int j = 0; j < 10; j++) {
                               System. out.println( this.hashCode() + ":" + j);
                               Thread. sleep(this.hashCode()%2);
                          } 
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System. out.println(String. format("thread %d finished", this.hashCode()));
                  }
              });
          }         
          executor.shutdown();
      }
在任务执行完后,调用shutdown方法,将线程池中的空闲线程回收。该方法会使得keepAliveTime参数失效。
 
 

解决Java线程池任务执行完毕后线程回收问题的更多相关文章

  1. C# 多线程 线程池(ThreadPool) 2 如何控制线程池?

    线程池启动了,但是没有方法去控制线程池,如果子线程出现了问题,难道线程池就死了吗? 我们可以设置线程池的线程数量,进行加入任务,线程池会自动分配并且合理的执行,但是控制不了又有啥意思呢. 线程池里线程 ...

  2. java并发编程(四) 线程池 & 任务执行、终止源码分析

    参考文档 线程池任务执行全过程:https://blog.csdn.net/wojiaolinaaa/article/details/51345789 线程池中断:https://www.cnblog ...

  3. C# 本进程执行完毕后再执行下一线程

    最近做了一套MES集成系统,由上料到成品使自动化运行,其中生产过程是逐步的,但是每一个动作都需要独立的线程进行数据监听,那么就需要实现线程等待. 代码: using System; using Sys ...

  4. 解决批处理命令执行完毕后自动关闭cmd窗口方法

    问题描述: 日常开发工作中,为了节省多余操作导致浪费时间,我们经常会自己建一些批处理脚本文件(xx.bat),文件中包含我们需要执行的命令,有时候我们希望执行完毕后看一下执行的结果,但是窗口执行完毕后 ...

  5. 戏(细)说Executor框架线程池任务执行全过程(下)

    上一篇文章中通过引入的一个例子介绍了在Executor框架下,提交一个任务的过程,这个过程就像我们老大的老大要找个老大来执行一个任务那样简单.并通过剖析ExecutorService的一种经典实现Th ...

  6. Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程

    下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...

  7. 戏(细)说Executor框架线程池任务执行全过程(上)

    一.前言 1.5后引入的Executor框架的最大优点是把任务的提交和执行解耦.要执行任务的人只需把Task描述清楚,然后提交即可.这个Task是怎么被执行的,被谁执行的,什么时候执行的,提交的人就不 ...

  8. Android AsyncTask内部线程池异步执行任务机制简要分析

    如下分析针对的API 25的AsyncTask的源码: 使用AsyncTask如果是调用execute方法则是同步执行任务,想要异步执行任务可以直接调用executeOnExecutor方法,多数情况 ...

  9. java线程池与五种常用线程池策略使用与解析

    背景:面试中会要求对5中线程池作分析.所以要熟知线程池的运行细节,如CachedThreadPool会引发oom吗? java线程池与五种常用线程池策略使用与解析 可选择的阻塞队列BlockingQu ...

随机推荐

  1. Power-Aware GateSim Debug

    For PAG debug, the following steps may be useful. 1. Get correct netlists from PD which contain powe ...

  2. UVa 1343 The Rotation Game (状态空间搜索 && IDA*)

    题意:有个#字型的棋盘,2行2列,一共24个格. 如图:每个格子是1或2或3,一共8个1,8个2,8个3. 有A~H一共8种合法操作,比如A代表把A这一列向上移动一个,最上面的格会补到最下面. 求:使 ...

  3. luogu P1141 01迷宫 x

    P1141 01迷宫 题目描述 有一个仅由数字0与1组成的n×n格迷宫.若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上. 你的任 ...

  4. K8S简介

    简介 Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规 ...

  5. 神经网络内在逻辑:没打开的AI“黑匣子”

    转载自:http://www.elecfans.com/rengongzhineng/592200.html 伴随着大数据,AI在沉寂了多年之后,又迎来了新的高潮.在这场涉及大部分科学的革命中,人工神 ...

  6. 在Sublime Text 3中配置Python3的开发环境/Build System

    本文来源:https://www.cnblogs.com/zhangqinwei/p/6886600.html Sublime Text作为一款支持多种编程语言的文本编辑神器,深受广大开发者的喜爱.通 ...

  7. Spring Boot教程(十七)属性配置文件详解(2)

    通过命令行设置属性值 相信使用过一段时间Spring Boot的用户,一定知道这条命令:java -jar xxx.jar --server.port=8888,通过使用–server.port属性来 ...

  8. Redis、Nginx加入启动命令

    1.redis加入系统启动命令 vim /etc/init.d/redis #!/bin/sh #chkconfig: 2345 80 90 # Simple Redis init.d script ...

  9. Ambari 2.6.0 HDP 2.6.3集群搭建

    1.安装环境说明 三台机器安装好CentOS-7-x86_64-Minimal-1708.iso 下载地址:https://www.centos.org/download/ 最好在安装时设置好IP和H ...

  10. python面向对象之设计模式

      概念: 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结.使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证代码可靠性. 设计 ...