多线程学习笔记(4)

in 四月桐花 with 0 comment

线程场景

如何根据不同的场景构建合适的线程池

下面是基础定义:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

IO密集型任务

由于CPU使用率不高,且每个人物CPU工作时间较短,可以增加线程池中工作的线程,提高执行效率

  1. corePoolSize为CPU核心线程数2倍
  2. corePoolSize=maximumPoolSize,保证优先使用扩展线程的方式分配任务,而非进入阻塞队列
  3. workQueue必须使用有界队列

CPU密集型任务

CPU密集型任务,单个任务需要占用CPU较长的工作时间,如果线程池中工作的线程过多,会导致CPU更频繁的切换任务,这种时间消耗会使任务效率下降.所以定的时候,线程数等于CPU核心数就行.

  1. corePoolSize为CPU核心线程数
  2. corePoolSize=maximumPoolSize,保证优先使用扩展线程的方式分配任务,而非进入阻塞队列
  3. workQueue必须使用有界队列

混合型任务

混合型任务可以通过公式计算出最佳线程数:

最佳线程数 = ((线程等待时间+线程CPU时间) / 线程CPU时间) * CPU核数

或:

最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1) * CPU核数

例如:WEB应用的HTTP请求,当请求到达后端时,任务的核心流程主要有两部分组成:

  1. 业务代码的执行,通常耗时较短(假定全程需要100ms)
  2. RPC,DB等IO操作,CPU几乎不工作,只需要等待资源(假定资源获取时cpu需要等待500ms)
  3. CPU物理核心为8core

此时理想线程数为: (500 + 100) / 100 * 8 = 48

corePoolSize: 核心线程池大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。
maximumPoolSize: 线程池中允许创建的最大线程数,线程池中的当前线程数目不会超过该值。如果队列中任务已满,并且当前线程个数(poolSize)小于maximumPoolSize,那么会创建新的线程来执行任务。
poorSize: 线程池中当前线程的数量,当该值为0的时候,意味着没有任何线程,线程池会终止;同一时刻,poolSize不会超过maximumPoolSize。

小结

线程池参数的定义对程序运行多线程效率有很大的影响,根据不同的使用场景,配置合适的线程池是十分重要的.