线程池优点
降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。 当任务到达时,任务可以不需要等到线程池创建就能立即执行。
提高线程的可管理性。 线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。但是,要做到合理利用线程池,必须对其实现原理了如指掌。
线程池创建 public ThreadPoolExecutor (int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
corePoolSize:线程池核心线程数量
maximumPoolSize:线程池最大线程数量
keepAliverTime:当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间
unit:存活时间的单位 (DAYS,HOURS,MINUTES,MILLISECONDS……)
workQueue:存放任务的队列
handler:超出线程范围和队列容量的任务的处理程序
线程池实现原理 提交一个任务到线程池中,线程池的处理流程如下:
1、判断线程池里的核心线程 是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3、判断线程池里的线程 是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
线程池源码解读 ThreadPoolExecutor的execute()方法 public void execute (Runnable command) { if (command == null ) throw new NullPointerException(); if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) { if (runState == RUNNING && workQueue.offer(command)) { if (runState != RUNNING || poolSize == 0 ) ensureQueuedTaskHandled(command); } else if (!addIfUnderMaximumPoolSize(command)) reject(command); } }
创建线程的方法:addIfUnderCorePoolSize(command) private boolean addIfUnderCorePoolSize (Runnable firstTask) { Thread t = null ; final ReentrantLock mainLock = this .mainLock; mainLock.lock(); try { if (poolSize < corePoolSize && runState == RUNNING) t = addThread(firstTask); } finally { mainLock.unlock(); } if (t == null ) return false ; t.start(); return true ; }
Worker类的run方法 public void run () { try { Runnable task = firstTask; firstTask = null ; while (task != null || (task = getTask()) != null ) { runTask(task); task = null ; } } finally { workerDone(this ); } }
worker在执行完任务后,还会通过getTask方法循环获取工作队里里的任务来执行。
线程池例子 public class ThreadPoolTest implements Runnable { @Override public void run () { try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main (String[] args) { LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(5 ); ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5 , 10 , 1 , TimeUnit.SECONDS, queue); for (int i = 0 ; i < 16 ; i++) { threadPool.execute( new Thread(new ThreadPoolTest(), "Thread" .concat(i + "" ))); System.out.println("线程池中活跃的线程数: " + threadPool.getPoolSize()); if (queue.size() > 0 ) { System.out.println("----------------队列中阻塞的线程数" + queue.size()); } } threadPool.shutdown(); } }
从结果可以观察出:
1、创建的线程池具体配置为:核心线程数量为5个;全部线程数量为10个;工作队列的长度为5。
2、我们通过queue.size()的方法来获取工作队列中的任务数。
3、运行原理:
刚开始都是在创建新的线程,达到核心线程数量5个后,新的任务进来后不再创建新的线程,而是将任务加入工作队列,任务队列到达上线5个后,新的任务又会创建新的普通线程,直到达到线程池最大的线程数量10个,后面的任务则根据配置的饱和策略来处理。我们这里没有具体配置,使用的是默认的配置AbortPolicy:直接抛出异常。
当然,为了达到我需要的效果,上述线程处理的任务都是利用休眠导致线程没有释放!!!