线程池(一)

线程池重要参数

1.构造方法参数讲解

参数名 作用
corePoolSize 队列未满时,线程最大并发数;核心线程池大小如:80
maximumPoolSize 队列满后线程能够到达的最大并发数;最大线程池大小如:100
keepAliveTime

线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间

大于80剩余线程存活的时间

TimeUnit keepAliveTime时间单位 大于80剩余线程存活的时间
workQueue

阻塞任务队列 :大于80之后进入该queue

如corePoolSize=5 实际有10个线程,超出的5个将会存放到待队列里

threadFactory 新建线程工厂
RejectedExecutionHandler

当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理;

如maxmumPoolSize=5,workQueue的size=2,实际最大线程为10>7超出的3个线程将会提交给RejectedExecutionHandler

2.拒绝策略代码演示:

public class RejectedExecutionHandlerAction implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        executor.allowCoreThreadTimeOut(true);
        System.out.println("aaa"+ executor.getActiveCount());
    }
}
 public void test() throws InterruptedException {
        //队列不限定长度 无论实际有多少个线程都不会触发 RejectedExecutionHandler
        LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque();
        RejectedExecutionHandlerAction action = new RejectedExecutionHandlerAction();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 5, TimeUnit.SECONDS, linkedBlockingDeque, action );
        for (int i = 0; i < 10; i++) {
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(" 线程名称:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入printA");
                }
            });
        }
        System.out.println(linkedBlockingDeque.size());
        Thread.sleep(20000);
        System.out.println(linkedBlockingDeque.size());
    }

运行结果:

指定队列长度,超出线程触发RejectedExecutionHandler

LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque(2);

  1. corePoolSize,maximumPoolSize,workQueue之间关系。

    1. 当线程池中线程数小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。

    2. 当线程池中线程数达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 。

    3. 当workQueue已满,且maximumPoolSize > corePoolSize时,新提交任务会创建新线程执行任务。

    4. 当workQueue已满,且提交任务数超过maximumPoolSize,任务由RejectedExecutionHandler处理。

    5. 当线程池中线程数超过corePoolSize,且超过这部分的空闲时间达到keepAliveTime时,回收这些线程。

    6. 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize范围内的线程空闲时间达到keepAliveTime也将回收。

3.线程管理机制图示

 

 

 

   

Executors提供的线程池配置方案 

1、newFixedThreadPool

构造一个固定线程数目的线程池,配置的corePoolSize与maximumPoolSize大小相同,同时使用了一个无界LinkedBlockingQueue存放阻塞任务,因此多余的任务将存在再阻塞队列,不会由RejectedExecutionHandler处理 

 

 

ExecutorService executorService = Executors.newFixedThreadPool(10);
  1. public static ExecutorService newFixedThreadPool(int nThreads) {  
  2. return new ThreadPoolExecutor(nThreads, nThreads,  
  3.                                       0L, TimeUnit.MILLISECONDS,  
  4. new LinkedBlockingQueue<Runnable>());  
  5.     }  

 

 

 

 

 


2、newCachedThreadPool

构造一个缓冲功能的线程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一个无容量的阻塞队列 SynchronousQueue,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s将会销毁

  

 ExecutorService executorService2 = Executors.newCachedThreadPool();
       public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
  

非核心线程Worker未执行完当前Task,创建新的Worker接收新的Task

 

线程复用

注释掉sleep代码再次执行如下:

线程51执行多个任务

pool-3-thread-51--执行项目51
pool-3-thread-51--执行项目277
pool-3-thread-51--执行项目398
pool-3-thread-51--执行项目527

 

 


3、newSingleThreadPool

构造一个只支持一个线程的线程池,配置corePoolSize=maximumPoolSize=1,无界阻塞队列LinkedBlockingQueue;保证任务由一个线程串行执行

 

 

 

 ExecutorService executorService1 = Executors.newSingleThreadExecutor();
       

只有一个线程在干活

 

4、newScheduledThreadPool

构造有定时功能的线程池,配置corePoolSize,无界延迟阻塞队列DelayedWorkQueue;有意思的是:maximumPoolSize=Integer.MAX_VALUE,由于DelayedWorkQueue是无界队列,所以这个值是没有意义的

 
    1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {  
    2. return new ScheduledThreadPoolExecutor(corePoolSize);  
    3.     }  
    4. public static ScheduledExecutorService newScheduledThreadPool(  
    5. int corePoolSize, ThreadFactory threadFactory) {  
    6. return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);  
    7.     }  
    8. public ScheduledThreadPoolExecutor(int corePoolSize,  
    9.                              ThreadFactory threadFactory) {  
    10. super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,  
    11. new DelayedWorkQueue(), threadFactory);  
    12.     }  

线程池中execute和submit的区别

submit有返回值execute没有返回值,submit底层还是 调用的execute方法

submit方法:

  public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

实现原理:

 

类图

 

 

 拒绝策略

当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:

  1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。(默认策略)
  2. ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
  3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务(丢弃老任务,接收新任务)
  4. ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
posted @ 2019-08-14 16:37  暖暖-木木  阅读(190)  评论(0编辑  收藏  举报