一、简介
线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,

long keepAliveTime, TimeUnit unit,

BlockingQueue<Runnable> workQueue,

RejectedExecutionHandler handler)

corePoolSize: 线程池维护线程的最少数量

maximumPoolSize:线程池维护线程的最大数量

keepAliveTime: 线程池维护线程所允许的空闲时间

unit: 线程池维护线程所允许的空闲时间的单位

workQueue: 线程池所使用的缓冲队列

handler: 线程池对拒绝任务的处理策略

一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。

当一个任务通过execute(Runnable)方法欲添加到线程池时:

如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。

也就是:处理任务的优先级为:

核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:

NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue

handler有四个选择:

ThreadPoolExecutor.AbortPolicy()

抛出java.util.concurrent.RejectedExecutionException异常

ThreadPoolExecutor.CallerRunsPolicy()

重试添加当前的任务,他会自动重复调用execute()方法

ThreadPoolExecutor.DiscardOldestPolicy()

抛弃旧的任务

ThreadPoolExecutor.DiscardPolicy()

抛弃当前的任务

二、一般用法举例

  1. package demo;
  2. import java.io.Serializable;
  3. import java.util.concurrent.ArrayBlockingQueue;
  4. import java.util.concurrent.ThreadPoolExecutor;
  5. import java.util.concurrent.TimeUnit;
  6. public class TestThreadPool2
  7. {
  8. private static int produceTaskSleepTime = 2;
  9. private static int produceTaskMaxNumber = 10;
  10. public static void main(String[] args)
  11. {
  12. // 构造一个线程池
  13. ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
  14. new ThreadPoolExecutor.DiscardOldestPolicy());
  15. for (int i = 1; i <= produceTaskMaxNumber; i++)
  16. {
  17. try
  18. {
  19. // 产生一个任务,并将其加入到线程池
  20. String task = "task@ " + i;
  21. System.out.println("put " + task);
  22. threadPool.execute(new ThreadPoolTask(task));
  23. // 便于观察,等待一段时间
  24. Thread.sleep(produceTaskSleepTime);
  25. }
  26. catch (Exception e)
  27. {
  28. e.printStackTrace();
  29. }
  30. }
  31. }
  32. }
  33. /**
  34. * 线程池执行的任务
  35. */
  36. class ThreadPoolTask implements Runnable, Serializable
  37. {
  38. private static final long serialVersionUID = 0;
  39. private static int consumeTaskSleepTime = 2000;
  40. // 保存任务所需要的数据
  41. private Object threadPoolTaskData;
  42. ThreadPoolTask(Object tasks)
  43. {
  44. this.threadPoolTaskData = tasks;
  45. }
  46. public void run()
  47. {
  48. // 处理一个任务,这里的处理方式太简单了,仅仅是一个打印语句
  49. System.out.println(Thread.currentThread().getName());
  50. System.out.println("start .." + threadPoolTaskData);
  51. try
  52. {
  53. // //便于观察,等待一段时间
  54. Thread.sleep(consumeTaskSleepTime);
  55. }
  56. catch (Exception e)
  57. {
  58. e.printStackTrace();
  59. }
  60. threadPoolTaskData = null;
  61. }
  62. public Object getTask()
  63. {
  64. return this.threadPoolTaskData;
  65. }
  66. }

说明:

1、在这段程序中,一个任务就是一个Runnable类型的对象,也就是一个ThreadPoolTask类型的对象。

2、一般来说任务除了处理方式外,还需要处理的数据,处理的数据通过构造方法传给任务。

3、在这段程序中,main()方法相当于一个残忍的领导,他派发出许多任务,丢给一个叫 threadPool的任劳任怨的小组来做。

这个小组里面队员至少有两个,如果他们两个忙不过来,任务就被放到任务列表里面。

如果积压的任务过多,多到任务列表都装不下(超过3个)的时候,就雇佣新的队员来帮忙。但是基于成本的考虑,不能雇佣太多的队员,至多只能雇佣 4个。

如果四个队员都在忙时,再有新的任务,这个小组就处理不了了,任务就会被通过一种策略来处理,我们的处理方式是不停的派发,直到接受这个任务为止(更残忍!呵呵)。

因为队员工作是需要成本的,如果工作很闲,闲到 3SECONDS都没有新的任务了,那么有的队员就会被解雇了,但是,为了小组的正常运转,即使工作再闲,小组的队员也不能少于两个。

4、通过调整 produceTaskSleepTime和 consumeTaskSleepTime的大小来实现对派发任务和处理任务的速度的控制,改变这两个值就可以观察不同速率下程序的工作情况。

5、通过调整4中所指的数据,再加上调整任务丢弃策略,换上其他三种策略,就可以看出不同策略下的不同处理方式。

6、对于其他的使用方法,参看jdk的帮助,很容易理解和使用。

另一个例子:

    1. package demo;
    2. import java.util.Queue;
    3. import java.util.concurrent.ArrayBlockingQueue;
    4. import java.util.concurrent.ThreadPoolExecutor;
    5. import java.util.concurrent.TimeUnit;
    6. public class ThreadPoolExecutorTest
    7. {
    8. private static int queueDeep = 4;
    9. public void createThreadPool()
    10. {
    11. /*
    12. * 创建线程池,最小线程数为2,最大线程数为4,线程池维护线程的空闲时间为3秒,
    13. * 使用队列深度为4的有界队列,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,
    14. * 然后重试执行程序(如果再次失败,则重复此过程),里面已经根据队列深度对任务加载进行了控制。
    15. */
    16. ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueDeep),
    17. new ThreadPoolExecutor.DiscardOldestPolicy());
    18. // 向线程池中添加 10 个任务
    19. for (int i = 0; i < 10; i++)
    20. {
    21. try
    22. {
    23. Thread.sleep(1);
    24. }
    25. catch (InterruptedException e)
    26. {
    27. e.printStackTrace();
    28. }
    29. while (getQueueSize(tpe.getQueue()) >= queueDeep)
    30. {
    31. System.out.println("队列已满,等3秒再添加任务");
    32. try
    33. {
    34. Thread.sleep(3000);
    35. }
    36. catch (InterruptedException e)
    37. {
    38. e.printStackTrace();
    39. }
    40. }
    41. TaskThreadPool ttp = new TaskThreadPool(i);
    42. System.out.println("put i:" + i);
    43. tpe.execute(ttp);
    44. }
    45. tpe.shutdown();
    46. }
    47. private synchronized int getQueueSize(Queue queue)
    48. {
    49. return queue.size();
    50. }
    51. public static void main(String[] args)
    52. {
    53. ThreadPoolExecutorTest test = new ThreadPoolExecutorTest();
    54. test.createThreadPool();
    55. }
    56. class TaskThreadPool implements Runnable
    57. {
    58. private int index;
    59. public TaskThreadPool(int index)
    60. {
    61. this.index = index;
    62. }
    63. public void run()
    64. {
    65. System.out.println(Thread.currentThread() + " index:" + index);
    66. try
    67. {
    68. Thread.sleep(3000);
    69. }
    70. catch (InterruptedException e)
    71. {
    72. e.printStackTrace();
    73. }
    74. }
    75. }
    76. }

线程池ThreadPoolExecutor使用简介的更多相关文章

  1. java线程池ThreadPoolExecutor使用简介

    一.简介线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:ThreadPoolExecutor(int corePoolSize, int m ...

  2. 线程池ThreadPoolExecutor使用简介(转)

    一.简介 线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, int ...

  3. [转载]线程池ThreadPoolExecutor使用简介

    一.简介 线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, int ...

  4. 关于线程池ThreadPoolExecutor使用总结

    本文引用自: http://blog.chinaunix.net/uid-20577907-id-3519578.html 一.简介 线程池类为 java.util.concurrent.Thread ...

  5. 多线程学习笔记八之线程池ThreadPoolExecutor实现分析

    目录 简介 继承结构 实现分析 ThreadPoolExecutor类属性 线程池状态 构造方法 execute(Runnable command) addWorker(Runnable firstT ...

  6. 线程池ThreadPoolExecutor使用

    一.简介 线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, int ...

  7. 线程池ThreadPoolExecutor

    线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, int maxi ...

  8. [转] 引用 Java自带的线程池ThreadPoolExecutor详细介绍说明和实例应用

    PS: Spring ThreadPoolTaskExecutor vs Java Executorservice cachedthreadpool 引用 [轰隆隆] 的 Java自带的线程池Thre ...

  9. android线程池ThreadPoolExecutor的理解

    android线程池ThreadPoolExecutor的理解 线程池 我自己理解看来.线程池顾名思义就是一个容器的意思,容纳的就是ThreadorRunable, 注意:每一个线程都是需要CPU分配 ...

随机推荐

  1. Asp.Net 前后台交互小结

    转自:http://blog.csdn.net/wlccomeon/article/details/17270427 一.前台调用后台           前台调用后台的方法一共可分为两大类:使用Ht ...

  2. VS2010引用项目dll,编译时报错

    截图出处:http://www.cnblogs.com/wuhuisheng/archive/2012/02/13/2349754.html

  3. python 零散记录(一) input与raw_input 数学相关函数 转换字符串的方法

    input()与raw_input(): 两者都是接受命令行输入,但区别在于,raw_input()接受原始数据(raw data). #使用input()来提示输入名字 input("en ...

  4. JSP控制select不可再选择

    首先分析下disable ,display和readonly: 1,Readonly只针对input(text / password)和textarea有效,而disabled对于所有的表单元素都有效 ...

  5. bzoj 2618 2618: [Cqoi2006]凸多边形(半平面交)

    2618: [Cqoi2006]凸多边形 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 656  Solved: 340[Submit][Status] ...

  6. SublimeText3使用技巧总结

    Ctrl + R : 查找函数和变量 Ctrl + P: 查找当前工程下面的文件 Ctrl + ":" : 查找变量 Ctrl + "g" : 输入行数跳转到指 ...

  7. 一步一步写一个简单通用的makefile(四)--写一个通用的makefile编译android可执行文件

    通常要把我们自己的的代码编译成在android里面编译的可执行文件,我们通常是建一个文件夹 . ├── Android.mk ├── Application.mk ├── convolve.cl ├─ ...

  8. HW4.26

    public class Solution { public static void main(String[] args) { double sum; double item; for(int i ...

  9. Project Euler 9

    题意:三个正整数a + b + c = 1000,a*a + b*b = c*c.求a*b*c. 解法:可以暴力枚举,但是也有数学方法. 首先,a,b,c中肯定有至少一个为偶数,否则和不可能为以上两个 ...

  10. Mockito测试

    Mockito 一 mockito基本概念 Mock测试是单元测试的重要方法之一,而Mockito作为一个流行的Mock框架,简单易学,且有非常简洁的API,测试代码的可读性很高. Mock测试就是在 ...