5.任务拒绝策略
  当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来会采取任务拒绝策略,通常有以下四种策略:
  ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列前面的任务,然后重新尝试执行任务(重复此过程)
  ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
  6.线程池的关闭
  ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:
  shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
  shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
  7.线程池容量的动态调整
  ThreadPoolExecutor提供了动态调整线程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),
  setCorePoolSize:设置核心池大小
  setMaximumPoolSize:设置线程池大能创建的线程数目大小
  当上述参数从小变大时,ThreadPoolExecutor进行线程赋值,还可能立即创建新的线程来执行任务。
  三.使用示例
  前面我们讨论了关于线程池的实现原理,这一节我们来看一下它的具体使用:
  public class Test {
  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);
  executor.execute(myTask);
  System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
  executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());
  }
  executor.shutdown();
  }
  }
  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(4000);
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  System.out.println("task "+taskNum+"执行完毕");
  }
  }
  执行结果:
  正在执行task 0
  线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
  线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
  正在执行task 1
  线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
  正在执行task 2
  线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
  正在执行task 3
  线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
  正在执行task 4
  线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0
  线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
  线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0
  线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0
  线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
  线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
  正在执行task 10
  线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
  正在执行task 11
  线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
  正在执行task 12
  线程池中线程数目:9,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
  正在执行task 13
  线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
  正在执行task 14
  task 3执行完毕
  task 0执行完毕
  task 2执行完毕
  task 1执行完毕
  正在执行task 8
  正在执行task 7
  正在执行task 6
  正在执行task 5
  task 4执行完毕
  task 10执行完毕
  task 11执行完毕
  task 13执行完毕
  task 12执行完毕
  正在执行task 9
  task 14执行完毕
  task 8执行完毕
  task 5执行完毕
  task 7执行完毕
  task 6执行完毕
  task 9执行完毕
  从执行结果可以看出,当线程池中线程的数目大于5时,便将任务放入任务缓存队列里面,当任务缓存队列满了之后,便创建新的线程。如果上面程序中,将for循环中改成执行20个任务,会抛出任务拒绝异常了。
  不过在java doc中,并不提倡我们直接使用ThreadPoolExecutor,而是使用Executors类中提供的几个静态方法来创建线程池:
  Executors.newCachedThreadPool();        //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
  Executors.newSingleThreadExecutor();   //创建容量为1的缓冲池
  Executors.newFixedThreadPool(int);    //创建固定容量大小的缓冲池
  下面是这三个静态方法的具体实现:
  public static ExecutorService newFixedThreadPool(int nThreads) {
  return new ThreadPoolExecutor(nThreads, nThreads,
  0L, TimeUnit.MILLISECONDS,
  new LinkedBlockingQueue<Runnable>());
  }
  public static ExecutorService newSingleThreadExecutor() {
  return new FinalizableDelegatedExecutorService
  (new ThreadPoolExecutor(1, 1,
  0L, TimeUnit.MILLISECONDS,
  new LinkedBlockingQueue<Runnable>()));
  }
  public static ExecutorService newCachedThreadPool() {
  return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  60L, TimeUnit.SECONDS,
  new SynchronousQueue<Runnable>());
  }
  从它们的具体实现来看,它们实际上也是调用了ThreadPoolExecutor,只不过参数都已配置好了。
  newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的LinkedBlockingQueue;
  newSingleThreadExecutor将corePoolSize和maximumPoolSize都设置为1,也使用的LinkedBlockingQueue;
  newCachedThreadPool将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使用的SynchronousQueue,也是说来了任务创建线程运行,当线程空闲超过60秒,销毁线程。
  实际中,如果Executors提供的三个静态方法能满足要求,尽量使用它提供的三个方法,因为自己去手动配置ThreadPoolExecutor的参数有点麻烦,要根据实际任务的类型和数量来进行配置。
  另外,如果ThreadPoolExecutor达不到要求,可以自己继承ThreadPoolExecutor类进行重写。