概述:
线程池机制是事先创建一些线程等待服务端程序的调用,这些线程保存在一个数组结构中,称为“线程池”。当服务器有任务执行时,就从线程池中取出一个线程并给其分配任务,当线程任务执行完成后,再被放回线程池中。
优点:
1. 由于在任务到达之前,线程已经存在,所以这里为系统消除了线程创建的资源和时间的开销。可以立即为请求服务,使程序响应更快。
2. 通过适当地调节线程池中的线程数目,就强制使一些新到的任务处于等待状态,可以防止资源不足。
参考:
http://www.cnblogs.com/dolphin0520/p/3932921.html
《Java语言程序设计》——清华大学出版社
示例及分析:
MyTask.java
public class MyTask implements Runnable { private int taskNum; public MyTask(int num) { this.taskNum = num; } @Override public void run() { System.out.println("正在执行task " + taskNum); try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task " + taskNum + "执行完毕"); } }
上面的程序很简单,就只是去打印一些简单的信息。
Executor.java
public class Executor { public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5)); for (int i = 0; i < 15; i++) { MyTask myTask = new MyTask(i); if (!executor.isShutdown()) { executor.execute(myTask); } printExecutor(executor); } executor.shutdown(); } private static void printExecutor(ThreadPoolExecutor executor) { System.out.println("线程池中线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" + executor.getQueue().size() + ",已执行完别的任务数目:" + executor.getCompletedTaskCount()); } }
上面用到了java为我们提供的类ThreadPoolExecutor,这是一个很好的类。上面用到创建实例时用到的构造器如下:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
它包含了下面这只个参数:
int corePoolSize:线程池中线程数
int maximumPoolSize:线程池中最大的线程数
long keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止
TimeUnit unit:参数keepAliveTime的时间单位,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS; //天 TimeUnit.HOURS; //小时 TimeUnit.MINUTES; //分钟 TimeUnit.SECONDS; //秒 TimeUnit.MILLISECONDS; //毫秒 TimeUnit.MICROSECONDS; //微妙 TimeUnit.NANOSECONDS; //纳秒
BlockingQueue<Runnable> workQueue:一个阻塞队列,用来存储等待执行的任务
<pre name="code" class="java">ArrayBlockingQueue; LinkedBlockingQueue; SynchronousQueue;
上面代码中使用的是ArrayBlockingQueue阻塞队列,并传入了参数5。这里有一点需要注意一下,如果我们假设所有任务数为mTaskCount(即代码中的15),那么我们最好去满足这样一个公式:maximumPoolSize >= mTaskCount - corePoolSize,不然就会抛出一个java.util.concurrent.RejectedExecutionException异常。当然,你也可以有一个通用的行为:将maximumPoolSize设置为Integer.MAX_VALUE。
还有一种方式可以补救:
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
不过目前可能大家对ThreadPoolExecutor的使用可能也不那么频繁了。因为Java为我们封装好了一些更方便的创建方式:
ExecutorService executor1 = Executors.newFixedThreadPool(5); // 创建固定容量大小的缓冲池 ExecutorService executor2 = Executors.newSingleThreadExecutor(); // 创建容量为1的缓冲池 ExecutorService executor3 = Executors.newCachedThreadPool(); // 创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
下面是上面三种创建方式对应的结果输出:
创建固定容量大小的缓冲池
正在执行task 0 正在执行task 2 正在执行task 4 正在执行task 1 正在执行task 3 task 4执行完毕 正在执行task 5 task 0执行完毕 正在执行task 6 task 2执行完毕 正在执行task 7 task 1执行完毕 正在执行task 8 task 3执行完毕 正在执行task 9 task 5执行完毕 task 7执行完毕 正在执行task 10 task 6执行完毕 正在执行task 11 正在执行task 12 task 9执行完毕 正在执行task 13 task 8执行完毕 正在执行task 14 task 11执行完毕 task 12执行完毕 task 10执行完毕 task 13执行完毕 task 14执行完毕
创建容量为1的缓冲池
正在执行task 0 task 0执行完毕 正在执行task 1 task 1执行完毕 正在执行task 2 task 2执行完毕 正在执行task 3 task 3执行完毕 正在执行task 4 task 4执行完毕 正在执行task 5 task 5执行完毕 正在执行task 6 task 6执行完毕 正在执行task 7 task 7执行完毕 正在执行task 8 task 8执行完毕 正在执行task 9 task 9执行完毕 正在执行task 10 task 10执行完毕 正在执行task 11 task 11执行完毕 正在执行task 12 task 12执行完毕 正在执行task 13 task 13执行完毕 正在执行task 14 task 14执行完毕
创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
正在执行task 0 正在执行task 2 正在执行task 4 正在执行task 6 正在执行task 8 正在执行task 10 正在执行task 12 正在执行task 14 正在执行task 1 正在执行task 3 正在执行task 5 正在执行task 9 正在执行task 7 正在执行task 11 正在执行task 13 task 2执行完毕 task 8执行完毕 task 6执行完毕 task 4执行完毕 task 0执行完毕 task 10执行完毕 task 14执行完毕 task 12执行完毕 task 1执行完毕 task 3执行完毕 task 5执行完毕 task 7执行完毕 task 9执行完毕 task 13执行完毕 task 11执行完毕
RejectedExecutionException异常:
http://blog.csdn.net/wzy_1988/article/details/38922449