Java并发编程笔记6:线程池的使用

ThreadPoolExecutor

在 Executoors 中的 newChachedThreadPool, newFixedThreadPool, newScheduledThreadExecutor 的工厂方法返回的都是 ThreadPoolExecutor 对象。若是默认的执行策略不能知足需求,能够经过 ThreadPoolExecutor 的构造函数进行实例化,根据本身的需求定制。 html

)

ThreadPoolExecutor(int corePoolSize,//线程池基本大小
                   int maximumPoolSize, //线程池最大尺寸
                   long keepAliveTime, //线程空闲后的存活时间
                   TimeUnit unit, 
                   BlockingQueue<Runnable> workQueue, //任务队列
                   ThreadFactory threadFactory, //线程工厂 
                   RejectedExecutionHandler handler) //饱和策略
复制代码

线程建立和销毁

  • corePoolSize是线程池的基本大小,即在没有任务执行时线程池的大小。
    • 在建立了线程池后,默认状况下,线程池中并无任何线程,而是等待有任务到来才建立线程去执行任务。
    • 能够调用prestartAllCoreThreads()或者prestartCoreThread()方法预建立线程,即在没有任务到来以前就建立corePoolSize个线程或者一个线程。
    • 默认状况下,在建立了线程池后,线程池中的线程数为0,当有任务来以后,就会建立一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中
    • 在工做队列满了的状况下才会建立超出这个数量的线程。
  • maximumPoolSize是线程池的最大尺寸,表示能够同时活动的线程数量的上限。
  • keepAliveTime 和 unit 共同表示了线程空闲后的存活时间
    • 默认状况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起做用,直到线程池中的线程数不大于corePoolSize。也就是当线程池中的线程数大于corePoolSize时,若是一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。
    • 若是调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起做用,直到线程池中的线程数为0

newFixedThreadPool 工厂方法将线程池的基本大小和最大大小都设置为参数中指定的值,并且建立的线程池不会超时。java

newCachedThreadPool工厂方法将线程池的最大大小设置为Integer.MAX_VALUE,将基本大小设置为0,并将超时设置为1分钟,这种方法建立出来的线程池能够被无限扩展,而且当需求下降时会自动收缩。git

管理队列任务

使用BlokcingQueue来保存等待执行的任务。基本的队列有无界队列,有界队列和同步移交。队列的选择和线程池的其余配置参数有关编程

newFixedThreadPool 和 newSingleThreadExecutor 在默认状况下使用一个无界的LinkedBlockingQueue。若是全部工做者线程都处于忙碌状态, 那么任务将在队列中等待。缓存

有界队列包括ArrayBlockingQueue以及有界的LinkedBlockingQueue和PriorityBlockingQueue。在使用有界队列时,队列的大小须要和线程池的大小一块儿调节。线程池小而队列较大,有助于减小内存使用量,下降CPU的使用率,同时还能够减小上下文切换,可是可能会限制吞吐量。并发

对于很是大或无界的线程池,能够经过SynchronousQueue来避免任务排队,以及直接将任务从生产者移交给工做者线程。这个队列的put方法会阻塞,直到有线程准备从队列里面take,因此本质上SynchronousQueue并非Queue,它不存储任何东西,它只是在移交东西,是一种在线程之间进行移交的机制。要将一个任务放到其中,必须有另外一个线程正在等待接受这个元素。若是没有线程正在等待,而且线程池的当前大小小于最大值,那么ThreadPoolExecutor将建立一个新的线程,不然这个任务奖杯拒绝。在 newCachedThreadPool中采用了SynchronousQueue。函数

饱和策略

当有界对垒被填满后,饱和策略开始发挥做用。经过setRejectedExecutionHandler来修改。有如下四种饱和策略。spa

  • AbortPolicy: 饱和策略,使用这种策略的线程池,将在没法继续接受新任务时,给任务提交方抛出RejectedExecutionException,让他们决定要如何处理
  • DiscardPolicy:抛弃策略,直接丢弃掉新来的任务
  • CallerRunsPolicy:调用者运行策略,这个策略,顾名思义,将把任务交给调用方所在的线程去执行
  • Discard-OldestPolicy: 抛弃最旧的策略,抛弃下一个奖杯执行的任务,而后尝试从新提交新的任务。(若是是优先级队列,会抛弃优先级最高的任务,最好不要一块儿使用)

线程工厂

线程池在建立线程时,经过线程工厂方法来完成。在默认的ThreadFactory接口中只定义了一个方法newThread,每当建立新线程时都会调用这个方法。能够本身建立一个类实现默认的ThreadFactory接口来定制本身的线程工厂。线程

扩展ThreadPoolExecutor

ThreadPoolExecutor是能够扩展的,它提供了几个能够在子类中改写的方法:beforeExecute, afterExecute, terminated。在执行任务的线程中将调用beforeExecute和afterExecute方法。不管是正常返回仍是抛出异常,afterExecute都被调用。若是beforeExecute抛出一个RuntimeException,任务将不被执行,afterExecute也不会调用。rest

参考资料

相关文章
相关标签/搜索