JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue

Posted ycr19921121

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue相关的知识,希望对你有一定的参考价值。

从Java5开始,Java提供了自己的线程池。每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池。以下是我的学习过程。

首先是构造函数签名如下:

  1. public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);   
参数介绍:

corePoolSize 核心线程数,指保留的线程池大小(不超过maximumPoolSize值时,线程池中最多有corePoolSize 个线程工作)。 
maximumPoolSize 指的是线程池的最大大小(线程池中最大有corePoolSize 个线程可运行)。 
keepAliveTime 指的是空闲线程结束的超时时间(当一个线程不工作时,过keepAliveTime 长时间将停止该线程)。 
unit 是一个枚举,表示 keepAliveTime 的单位(有NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS,7个可选值)。 
workQueue 表示存放任务的队列(存放需要被线程池执行的线程队列)。 
handler 拒绝策略(添加任务失败后如何处理该任务).

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:
    a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
    b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。
    c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;
    d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
       这个过程说明,并不是先加入任务就一定会先执行。假设队列大小为 4,corePoolSize为2,maximumPoolSize为6,那么当加入15个任务时,执行的顺序类似这样:首先执行任务 1、2,然后任务3~6被放入队列。这时候队列满了,任务7、8、9、10 会被马上执行,而任务 11~15 则会抛出异常。最终顺序是:1、2、7、8、9、10、3、4、5、6。当然这个过程是针对指定大小的ArrayBlockingQueue<Runnable>来说,如果是LinkedBlockingQueue<Runnable>,因为该队列无大小限制,所以不存在上述问题。

示例一,LinkedBlockingQueue<Runnable>队列使用:

  1. import java.util.concurrent.BlockingQueue;  
  2. import java.util.concurrent.LinkedBlockingQueue;  
  3. import java.util.concurrent.ThreadPoolExecutor;  
  4. import java.util.concurrent.TimeUnit;  
  5.   
  6. /** 
  7.  * Created on 2011-12-28 
  8.  * <p>Description: [Java 线程池学习]</p> 
  9.  * @author         [email protected] 
  10.  */  
  11. public class ThreadPoolTest implements Runnable {   
  12.      public void run() {   
  13.           synchronized(this) {   
  14.             try{  
  15.                 System.out.println(Thread.currentThread().getName());  
  16.                 Thread.sleep(3000);  
  17.             }catch (InterruptedException e){  
  18.                 e.printStackTrace();  
  19.             }  
  20.           }   
  21.      }   
  22.        
  23.      public static void main(String[] args) {   
  24.          BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();  
  25.          ThreadPoolExecutor executor = new ThreadPoolExecutor(261, TimeUnit.DAYS, queue);  
  26.          for (int i = 0; i < 10; i++) {     
  27.              executor.execute(new Thread(new ThreadPoolTest(), "TestThread".concat(""+i)));     
  28.              int threadSize = queue.size();  
  29.              System.out.println("线程队列大小为-->"+threadSize);  
  30.          }     
  31.          executor.shutdown();    
  32.      }  
  33. }   
  1. import java.util.concurrent.BlockingQueue;  
  2. import java.util.concurrent.LinkedBlockingQueue;  
  3. import java.util.concurrent.ThreadPoolExecutor;  
  4. import java.util.concurrent.TimeUnit;  
  5.   
  6. /** 
  7.  * Created on 2011-12-28 
  8.  * <p>Description: [Java 线程池学习]</p> 
  9.  * @author         [email protected] 
  10.  */  
  11. public class ThreadPoolTest implements Runnable {   
  12.      public void run() {   
  13.           synchronized(this) {   
  14.             try{  
  15.                 System.out.println(Thread.currentThread().getName());  
  16.                 Thread.sleep(3000);  
  17.             }catch (InterruptedException e){  
  18.                 e.printStackTrace();  
  19.             }  
  20.           }   
  21.      }   
  22.        
  23.      public static void main(String[] args) {   
  24.          BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();  
  25.          ThreadPoolExecutor executor = new ThreadPoolExecutor(261, TimeUnit.DAYS, queue);  
  26.          for (int i = 0; i < 10; i++) {     
  27.              executor.execute(new Thread(new ThreadPoolTest(), "TestThread".concat(""+i)));     
  28.              int threadSize = queue.size();  
  29.              System.out.println("线程队列大小为-->"+threadSize);  
  30.          }     
  31.          executor.shutdown();    
  32.      }  
  33. }   
输出结果如下:

线程队列大小为-->0
线程名称:pool-1-thread-1
线程队列大小为-->0
线程队列大小为-->1
线程队列大小为-->2
线程队列大小为-->3
线程队列大小为-->4
线程队列大小为-->5
线程队列大小为-->6
线程队列大小为-->7
线程队列大小为-->8
线程名称:pool-1-thread-2
线程名称:pool-1-thread-1
线程名称:pool-1-thread-2
线程名称:pool-1-thread-1
线程名称:pool-1-thread-2
线程名称:pool-1-thread-1
线程名称:pool-1-thread-2
线程名称:pool-1-thread-1
线程名称:pool-1-thread-2

可见,线程队列最大为8,共执行了10个线线程。因为是从线程池里运行的线程,所以虽然将线程的名称设为"TestThread".concat(""+i),但输出后还是变成了pool-1-thread-x。

示例二,LinkedBlockingQueue<Runnable>队列使用:

  1. import java.util.concurrent.BlockingQueue;  
  2. import java.util.concurrent.ArrayBlockingQueue;  
  3. import java.util.concurrent.ThreadPoolExecutor;  
  4. import java.util.concurrent.TimeUnit;  
  5.   
  6. /** 
  7.  * Created on 2011-12-28 
  8.  * <p>Description: [Java 线程池学习]</p> 
  9.  * @author         [email protected] 
  10.  */  
  11. public class ThreadPoolTest implements Runnable {   
  12.      public void run() {   
  13.    &nbs

    以上是关于JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue的主要内容,如果未能解决你的问题,请参考以下文章

    java线程池之ThreadPoolExecutor

    Java多线程系列——线程池原理之 ThreadPoolExecutor

    Java - "JUC线程池" ThreadPoolExecutor原理解析

    Java常用四大线程池用法以及ThreadPoolExecutor详解

    Java常用四大线程池用法以及ThreadPoolExecutor详解

    java线程池之ThreadPoolExecutor