对于经常使用第三方框架进行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. 字典,set

    字典 dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度 存取速度快 key-value存储方式,在放进去的时候,必须根据key算出v ...

  2. 结合webpack实现children子路由,抽离路由模块

    demo结构 package.json.webpack.config.js.index.html与上一篇博客相同. main.js // 这是项目的入口js文件 // import $ from 'j ...

  3. 容器适配器————stack

    只能访问 stack 顶部的元素:只有在移除 stack 顶部的元素后,才能访问下方的元素. 堆栈操作 top():返回一个栈顶元素的引用,类型为 T&.如果栈为空,返回值未定义. push( ...

  4. 【转】Python Schema一种优雅的数据验证方式

    转自 https://segmentfault.com/a/1190000011777230 Schema是什么? 不管我们做什么应用,只要和用户输入打交道,就有一个原则--永远不要相信用户的输入数据 ...

  5. sqli-labs(25a)

    0X01 看见bind好像是盲注的意思 尝试闭合语句 加入’ 报错  双引号也报错 难道是不许要闭合的? 我们尝试一下 发现过滤了and ?id= and = 那么我们构造 ?id= aandnd = ...

  6. android底部标题栏的实现

    一,使用TabActivity来实现底部导航 http://www.apkbus.com/forum.php?mod=viewthread&tid=125521 这种方法在最新版本的sdk中是 ...

  7. centos7 安装 chrome

    1. 配置yum源 在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repo cd /etc/yum.repos.d/ vim google-chrome.repo ...

  8. OOM和SOF代码

    OutOfMemoryError大数组,例如图片加载. public class MockOutOfMemoryError { public static void main(String[] arg ...

  9. CentOS7修改计算机名!

    https://www.cnblogs.com/acgpiano/p/4170546.html sudo hostnamectl set-hostname <host-name>

  10. Python深度学习读书笔记-1.什么是深度学习

    人工智能 什么是人工智能.机器学习与深度学习(见图1-1)?这三者之间有什么关系?