盘点java并发包提供的线程池和队列

线程池
  • newCachedThreadPool()
  • newFixedThreadPool(int nThreads)
  • newSingleThreadPoolExecutor()
  • newScheduledThreadPool(int corePoolSize)
  • newWorkStrealingPool(int parallelism)
队列
  • SynchronousQueue
  • LinkedBlockingQueue

线程池 Executors框架的5个静态工厂方法
  • CachedThreadPool
经常用来处理短时间任务的线程池,它试图缓存线程并重用,如果没有可用的缓存线程则新建线程,如果线程闲置60秒会移出缓存,这种线程池长时间闲置不会占用什么资源,但是如果任务并发出现速度过快会导致线程创建来不及处理任务导致部分任务等待超时。
  • FixedThreadPool
创建时接收缓存线程数参数,它只会缓存这么多线程,不会多也不会少,如果有工作线程退出,会创建新的线程补足指定数目。
它的工作队列是无界的,如果没有线程可用则会在队列中等待,这导致如果线程大小设置不合理以及任务并发大的情况下,请求类型的任务可能会导致请求超时。
为了避免上面的情况导致超时也好,队列任务过多导致oom也好,可以使用jmap等工具,查看是否有大量任务对象入队。
  • SingleThreadPool
它创建的是ScheduledExecutorService,可以定时或周期性的工作调度,线程数被限制为1,保证任务是顺序执行,线程池实例不能被修改。
  • ScheduledThreadPool
它创建的也是ScheduledExecutorService,区别在于它会保持核心线程在一定数量
  • WorkStrealingPool
内部构造ForkJoinPool,利用Work-Stealing 算法,并行处理任务,不保证处理顺序。
ThreadPoolExecutor 创建线程
new  ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds,runnableTaskQueue, handler);




• corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
• runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列。
• ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
• LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
• SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
• PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
• maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。
• ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。
• RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。
• AbortPolicy:直接抛出异常。
• CallerRunsPolicy:只用调用者所在线程来运行任务。
• DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
• DiscardPolicy:不处理,丢弃掉。
• 当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
• keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
• TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
向线程池提交任务
任务拒绝策略
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
• ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
• ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
• ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
• ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
自定义拒绝策略
/**
 * 线程池 请求数 大于 最大线程数+队列大小
 * @Author: duhongjiang
 * @Date: Created in 2018/6/24
 */
public abstract class MyRejectedExecutionHandler implements RejectedExecutionHandler {
    private static Logger logger = LoggerFactory.getLogger(MyRejectedExecutionHandler.class);
    @Override
    public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {
          rejected();
    }
    protected abstract void rejected();
}
线程池容量的动态调整
ThreadPoolExecutor提供了动态调整线程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize()
• setCorePoolSize:设置核心池大小
• setMaximumPoolSize:设置线程池最大能创建的线程数目大小

队列
  • SynchronousQueue
这个队列不会缓存任务,也就是说队列容量是0,来一个任务就交给线程,是CachedThreadPool使用的队列。
  • LinkedBlockingQueue
基于链表的先进先出 无界的队列,FixedThreadPool使用。但是 无界是相对说的,它的队列大小默认是Integer.MAX_VALUE,当然也可以指定大小。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值