线程池

通常都是用Executors提供的通用线程池创建方法,去创建不同的线程池。
Executors目前提供了5种不同的线程池创建配置:

  • newCachedThreadPool(),是一种处理大量短时间工作任务的线程
    特点:试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置时间超过60秒,则会被移出缓存。长时间闲置时,不会消耗资源。内部使用SynchronousQueue作为工作队列。
  • newFixedThreadPool(int nThreads),重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThread个工作线程是活动的。如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads。
  • newSingleThreadExecutor(),它的特点在于工作线程数目被限制为 1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目
  • newSingleThreadScheduledExecutor() 和 newScheduledThreadPool(int corePoolSize),创建的是个 ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程。
  • newWorkStealingPool(int parallelism),这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序。

核心线程:核心线程最大数量,通俗来说是线程池常驻线程的最大数量。线程池新建线程的时候,如果,当前线程总数小于corePoolSize,则新建的是核心线程,如果超过核心线程,则新建是非核心线程。

Java线程池实现原理及其在美团业务中的实践

Executor框架:
image.png

Executor是基础的接口,ExecutorService提供service的管理功能,如shutdown和任务的提交submit方法。
Java基础类库中提供了几种基础实现,ThreadPoolExecutor,ScheduledThreadPoolExecutor,ForkJoinPool。ScheduledThreadPoolExecutor是ThreadPoolExecutor扩展,主要增加调度逻辑。
线程池中的构造参数:

  • corePoolSizeL:核心线程数,即长期驻留的线程数。对于newFixedThreadPool会将其设置为nThread,对于newCachedThreadPool则为0;
  • maxmumPoolSize: 所能创建的最大的线程数。newFixedThreadPool,当然就是 nThreads,因为其要求是固定大小,而 newCachedThreadPool 则是 Integer.MAX_VALUE。
  • keepAliveTime 和 TimeUnit,这两个参数指定了额外的线程能够闲置多久,显然有些线程池不需要它。
  • workQueue,工作队列,必须是 BlockingQueue。
public ThreadPoolExecutor(int corePoolSize,
                      	int maximumPoolSize,
                      	long keepAliveTime,
                      	TimeUnit unit,
                      	BlockingQueue<Runnable> workQueue,
                      	ThreadFactory threadFactory,
                      	RejectedExecutionHandler handler)

线程池的实践:
避免任务堆积。newFixedThreadPool 是创建指定数目的线程,但是其工作队列是无界的,如果工作线程数目太少,导致处理跟不上入队的速度,有可能占用大量系统内存,甚至是出现 OOM。

避免过度扩展线程。在处理大量短时任务时,使用缓存的线程池,比如在最新的 HTTP/2 client API 中,目前的默认实现就是如此。

如果线程数目不断增长(可以使用 jstack 等工具检查),也需要警惕另外一种可能性,就是线程泄漏,这种情况往往是因为任务逻辑有问题,导致工作线程迟迟不能被释放。建议你排查下线程栈,很有可能多个线程都是卡在近似的代码处。

posted @ 2022-05-24 00:13  Baymax_HH  阅读(25)  评论(0编辑  收藏  举报