认识线程池
--|参考JDK API的理解:
线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。
--|其他理解:
--|减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
--|可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
--|假如创建线程的时间为t1,工作时间为t2,销毁时间为t3,当t1+t3>t2时,线程池的效率就更显而易见了。
Java5前后线程池
--|Java5之前的线程池实现
了解Java5以前的线程池实现利于理解线程池的工作原理,而Java5以后的线程池都已经帮我们做好这些事情,我们只需要调用适合自己的线程池即可。
原理:创建指定数量的线程池,这些线程排队到列里面读取任务,若发现任务则执行,否则当前线程处于睡眠状态。新任务则不断往队列里面添加,有任务后则唤醒沉睡中的线程。
--|Java5之后的线程池
Executors.newFixedThreadPool(poolSize);
固定大小的线程池。
Executors.newSingleThreadExecutor();
单个后台线程。
Executors.newCachedThreadPool();
无界线程池,可以进行自动线程回收。
Executors.newScheduledThreadPool(poolSize);
指定线程数的线程池,可在指定延迟后执行线程任务.。poolSize是池中所保存的线程数,即使线程是空闲的也被保存在线程池内。
Executors.newSingleThreadScheduledExecutor();
单个后台线程,可进行自动回收线程。
--|其中前3个方法返回的是ExecutorService对象,后两个方法返回的是ScheduledExecutorService对象。ScheduledExecutorService是ExecutorService的子类,可以指定延迟后执行线程任务。
--|Java7线程池
待学习。
线程池类层次结构图
线程池工作原理图
代码示例:Java5前
package com.java5.before; import java.util.LinkedList; /** * java5前线程池 * * @fileName ThreadPool.java * @date 2013-4-25 * @time 上午11:17:10 * @author wst * */ public class ThreadPool extends ThreadGroup { private boolean isClosed = false; // 线程池是否关闭 private LinkedList<Runnable> workQueue; // 工作队列,具有先进先出特征 private static int threadPoolID = 1; // 线程池的id /** * 创建指定大小的线程池 * * @param poolSize * 线程池中工作线程的数量 */ public ThreadPool(int poolSize) { super(threadPoolID + ""); // 指定ThreadGroup的名称 setDaemon(true); //标志为守护线程 workQueue = new LinkedList<Runnable>(); // 初始化工作队列 for (int i = 1; i <= poolSize; i++) { new WorkThread(i).start(); //启动线程池 } } /** * 向工作队列加入新任务,且通知空闲线程执行新任务 * * @date 2013-4-25 * @time 上午11:23:47 * @author wst * @param task * @return void */ public synchronized void addTaskForWorkQueue(Runnable task) { if (isClosed) { throw new IllegalStateException(); } if (task != null) { workQueue.add(task);// 向队列中加入一个任务 notify(); // 唤醒线程执行任务 } } /** * 从工作队列中取出一个任务,工作线程会调用此方法 * * @date 2013-4-25 * @time 上午11:26:58 * @author wst * @param threadid * @throws InterruptedException * @return Runnable */ private synchronized Runnable getTask(int threadid) throws InterruptedException { while (workQueue.size() == 0) { if (isClosed) { return null; } System.out.println("工作线程" + threadid + "等待任务..."); wait(); // 线程休息等待任务 } System.out.println("工作线程" + threadid + "获取到任务..."); return (Runnable) workQueue.removeFirst(); } /** * 关闭线程池 * @date 2013-4-25 * @time 上午11:30:41 * @author wst * @return void */ public synchronized void closePool() { if (!isClosed) { waitFinish(); // 等待工作线程执行完毕 isClosed = true; workQueue.clear(); // 清空工作队列 interrupt(); // 中断线程池中的所有的工作线程 } } /** * 等待工作线程把所有任务执行完毕 * @date 2013-4-25 * @time 上午11:30:53 * @author wst * @return void */ public void waitFinish() { synchronized (this) { isClosed = true; notifyAll(); // 唤醒所有还在getTask()方法中等待任务的工作线程 } Thread[] threads = new Thread[activeCount()]; // activeCount() // 返回该线程组中活动线程的估计值 int count = enumerate(threads); for (int i = 0; i < count; i++) { // 等待所有工作线程结束 try { threads[i].join(); // 等待工作线程结束 } catch (InterruptedException ex) { ex.printStackTrace(); } } } /** * 内部类,工作线程,负责从工作队列中取出任务,并执行 * @fileName ThreadPool.java * @date 2013-4-25 * @time 上午11:31:02 * @author wst * */ private class WorkThread extends Thread { private int id; /** * 取出指定id的任务 * @param id 任务id */ public WorkThread(int id) { // 父类构造方法,将线程加入到当前ThreadPool线程组中 super(ThreadPool.this, id + ""); this.id = id; } public void run() { while (!isInterrupted()) { // 判断线程是否被中断 Runnable task = null; try { task = getTask(id); // 取出任务 } catch (InterruptedException ex) { ex.printStackTrace(); } if (task == null){ return; } try { task.run(); } catch (Throwable t) { t.printStackTrace(); } } } } } package com.java5.before; /** * java5前线程池,测试 * * @fileName ThreadPoolTest.java * @date 2013-4-25 * @time 上午11:17:19 * @author wst * */ public class ThreadPoolTest { public static void main(String[] args) { //创建指定大小的线程池 ThreadPool threadPool = new ThreadPool(3); try { // 休眠500毫秒,以便让线程池中的工作线程全部运行 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 产生10个任务加入队列 for (int i = 1; i <= 10; i++) { threadPool.addTaskForWorkQueue(createTask(i)); } threadPool.waitFinish(); // 等待所有任务执行完毕 threadPool.closePool(); // 关闭线程池 } /** * 产生一个具体任务 * @date 2013-4-26 * @time 下午01:24:00 * @author wst * @param taskID * @return Runnable */ private static Runnable createTask(final int taskID) { return new Runnable() { public void run() { System.out.println("Task" + taskID + "开始"); System.out.println("Hello world"); System.out.println("Task" + taskID + "结束"); System.out.println(); } }; } }
代码示例:Java5后
package com.java5.after; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /*** * java5以后线程池 * * @fileName ThreadPool.java * @date 2013-4-28 * @time 下午01:25:44 * @author wst * */ public class ThreadPoolTest { /** * @date 2013-4-28 * @time 下午01:25:33 * @author wst * @param args * @return void */ @SuppressWarnings("unchecked") public static void main(String[] args) { ThreadPoolTest pool = new ThreadPoolTest(); // pool.testFixedThreadPool(3,10); pool.testSingleThreadExecutor(10); // pool.testCachedThreadPool(10); // pool.testScheduledThreadPool(2,10,3000,TimeUnit.MILLISECONDS); // pool.testSingleThreadScheduledExecutor(10,3000,TimeUnit.MILLISECONDS); //BlockingQueue bqueue = new ArrayBlockingQueue(20); // 创建等待队列 //pool.testUserDefinedThreadPool(10, 2, 5, 3000, TimeUnit.MILLISECONDS,bqueue); } /** * * 固定数量线程池 * 当要加入池的任务数量(taskCount)超过池最大尺寸(poolSize)时候 入此线程池则需要排队等待 * 线程池可重用 * * @date 2013-7-25 * @time 上午11:39:51 * @author wst * @param poolSize * 线程池大小 * @param taskCount * 任务数量 * @return void */ private void testFixedThreadPool(int poolSize, int taskCount) { ExecutorService pool = Executors.newFixedThreadPool(poolSize); for (int i = 1; i <= taskCount; i++) { pool.execute(new MyThread(i)); } pool.shutdown();// 关闭线程池 } /** * 单个后台线程 * * @date 2013-7-25 * @time 上午11:43:53 * @author wst * @param taskCount * 任务数量 * @return void */ private void testSingleThreadExecutor(int taskCount) { ExecutorService pool = Executors.newSingleThreadExecutor(); for (int i = 1; i <= taskCount; i++) { pool.execute(new MyThread(i)); } pool.shutdown(); } /** * 创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将被缓存在线程池中. * 创建一个可根据需要创建新线程的线程池, * 但是在以前构造的线程可用时将重用它们。 * 对于执行很多短期异步任务的程序而言, * 这些线程池通常可提高程序性能。 * 调用 execute 将重用以前构造的线程(如果线程可用)。 * 如果现有线程没有可用的,则创建一个新线程并添加到池中。 * 终止并从缓存中移除那些已有 60 秒钟未被使用的线程。 * 因此,长时间保持空闲的线程池不会使用任何资源。 * * @date 2013-7-25 * @time 上午11:45:41 * @author wst * @param taskCount * 任务数量 * @return void */ private void testCachedThreadPool(int taskCount) { ExecutorService pool = Executors.newCachedThreadPool(); for (int i = 1; i <= taskCount; i++) { pool.execute(new MyThread(i)); } pool.shutdown(); } /** * 创建具有指定线程数的线程池,它可以在指定延迟后执行线程任务. * poolSize是指池中所保存的线程数,即使线程是空闲的也被保存在线程池内. * * @date 2013-7-25 * @time 上午11:53:17 * @author wst * @param poolSize * @param taskCount * @param delay * 延迟时间 * @param unit * 时间单位 * @return void */ private void testScheduledThreadPool(int poolSize, int taskCount, long delay, TimeUnit unit) { ScheduledExecutorService pool = Executors.newScheduledThreadPool(poolSize); for (int i = 1; i <= taskCount; i++) { pool.execute((Runnable) pool.schedule(new MyThread(i), delay,unit)); } pool.shutdown(); } /** * 单线程延迟线程池 * * @date 2013-7-25 * @time 下午12:30:43 * @author wst * @param taskCount * @param delay * @param unit * @return void */ private void testSingleThreadScheduledExecutor(int taskCount, long delay, TimeUnit unit) { ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor(); for (int i = 1; i <= taskCount; i++) { pool.execute((Runnable) pool.schedule(new MyThread(i), delay,unit)); } pool.shutdown(); } /** * 自定义线程池 * * @date 2013-7-25 * @time 下午01:20:47 * @author wst * @param taskCount * 任务数量 * @param corePoolSize * 核心线程数量 * @param maximumPoolSize * 最大线程数量 * @param keepAliveTime * 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间 * @param unit * 时间单位 * @param workQueue * 队列 * @return void */ private void testUserDefinedThreadPool(int taskCount, int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { ThreadPoolExecutor pool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); for (int i = 1; i <= taskCount; i++) { pool.execute(new MyThread(i)); } pool.shutdown(); } }
package com.java5.after; /** * 我java5以后线程池,测试 * * @fileName MyThread.java * @date 2013-4-28 * @time 下午01:27:18 * @author wst * */ public class MyThread implements Runnable { private int i; public MyThread(int i){ this.i=i; } public void run() { try { Thread.sleep(500); System.out.println("线程"+Thread.currentThread().getName() +"正在执行 task="+i); } catch (InterruptedException e) { e.printStackTrace(); } } }
参数解读
corePoolSize - 池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute方法提交的 Runnable任务。
其他
强烈建议程序员使用较为方便的 Executors
工厂方法 Executors.newCachedThreadPool()
(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)
(固定大小线程池)和 Executors.newSingleThreadExecutor()
(单个后台线程),它们均为大多数使用场景预定义了设置。更多请参考JDK API1.6。