Java线程池的创建和使用

3 篇文章 0 订阅

什么是线程池?

线程池通俗的讲就是在程序启动时创建好若干个线程,供程序去调度和使用,当程序需要使用线程时不再需要去频繁的创建和销毁线程,而可以去线程池中获取空闲的线程直接使用,当使用完后线程进入空闲状态并非直接销毁线程。从JDK1.5开始,JAVA API的java.util.concurrent包下提供了Executors供开发人员方便的进行不同类型线程池的创建。

为什么使用线程池?

  1. 减小线程频繁创建和销毁对系统资源的消耗
  2. 提高系统响应速度,当系统需要使用线程时直接从池中获取
  3. 线程池可以根据实际情况进行调整,有效控制最大并发数

Executors创建常见的几种线程池

  • 创建固定大小的线程池:指定线程池核心线程数和最大线程数
ExecutorService executorService = Executors.newFixedThreadPool(8); 

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
}
  • 创建单个线程的线程池:仅有单线程执行任务,并按顺序执行
ExecutorService executorService = Executors.newSingleThreadExecutor();

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
  • 可缓存的线程池:线程数无限制,有空闲线程则复用,无空闲线程则创建。
ExecutorService executorService = Executors.newCachedThreadPool();

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
 }                                    
  • 定时线程池:可周期性或延时执行任务
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(8);

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
}

//延时执行(延迟10s执行dotask)
scheduledExecutorService.schedule(doTask(),10, TimeUnit.SECONDS);
//延迟10s开始执行dotask,每1s执行一次,下次执行时间=上次任务开始时间+时间间隔,任务执行时间不算在两次间隔时间内
scheduledExecutorService.scheduleAtFixedRate(doTask(),10,1,TimeUnit.SECONDS);
//延迟10s开始执行dotask,每1s执行一次,下次执行时间=上次任务执行结束时间+时间间隔,任务执行时间计算在两次间隔时间内
scheduledExecutorService.scheduleWithFixedDelay(doTask(),10,1,TimeUnit.SECONDS);

自定义线程池

虽然Executors工具类为我们提供了许多创建线程池的方法,但是都不推荐使用,推荐使用ThreadPoolExecutor进行线程的创建,如下为该类的几种构造方法:

//全部参数都自定义(共7个参数)
ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   TimeUnit unit,
                   BlockingQueue<Runnable> workQueue,
                   ThreadFactory threadFactory,
                   RejectedExecutionHandler handler){
			...
}
//使用默认的线程创建工厂(6个参数)
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
}
//使用默认的任务拒绝策略(6个参数)
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
      this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
           threadFactory, defaultHandler);
}           
//使用默认的线程创建工厂和默认的拒绝策略(5个参数)
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
}                    

不难发现,Executors创建线程池就是使用ThreadPoolExecutor进行创建的,只是不同的线程池使用了不同的固定参数,ThreadPoolExecutor类的全参构造共有七个参数,接下来对这些参数进行说明。

线程池创建时的参数

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   TimeUnit unit,
                   BlockingQueue<Runnable> workQueue,
                   ThreadFactory threadFactory,
                   RejectedExecutionHandler handler){
		...
}
  1. 核心线程数corePoolSize
    线程池的基本大小,当allowCoreThreadTimeOut=false(默认)时,线程池的线程数永远大于等于核心线程数(当线程已被创建的情况),即使当前没有任务要执行核心线程也不会被销毁。可以理解为线程池中的常驻线程就是核心线程,它永远不会被销毁。当核心线程全部处于运行状态,并且阻塞队列中等待的任务已满,线程池就会创建新的线程,此时创建的线程就是非核心线程,但核心线程+非核心线程的数量不能大于最大线程数。
  2. 最大线程数maximumPoolSize
    线程池中可存活的最大线程数量,核心线程数+非核心线程数<=最大线程数
  3. 线程(空闲)可存活时间keepAliveTime
    当线程池中的非核心线程在keepAliveTime的时间后依旧处于空闲状态,那么该线程就会被销毁。当allowCoreThreadTimeOut=true时,核心线程也会被销毁。
  4. 存活时间的单位unit
    keepAliveTime的单位,有如下单位:
          TimeUnit.NANOSECONDS 纳秒
          TimeUnit.MICROSECONDS 微秒
          TimeUnit.MILLISECONDS 毫秒
          TimeUnit.SECONDS 分钟
          TimeUnit.MINUTES 小时
          TimeUnit.HOURS 小时
          TimeUnit.DAYS 天
  5. 任务队列workQueue
    用于存储当线程全部被占用时等待执行的任务的阻塞队列。
  6. 线程工厂threadFactory
    指定线程池如何创建线程
  7. 拒绝策略handler
    当线程池线程数达到最大值,且阻塞队列的任务已满,指定对于新的任务该如何处理。

ThreadPoolExecutor类的其他成员变量

  • private volatile boolean allowCoreThreadTimeOut;
    核心线程是否有超时时间,如果为true,则空闲时间到达超时时间后销毁核心线程。
  • private final HashSet workers = new HashSet();
    用于存储当前线程池的线程,一个Worker即为一个线程。
  • private int largestPoolSize;
    线程池存活线程的历史最大值
  • private long completedTaskCount;
    线程池总共完成的任务总数
  • private volatile int corePoolSize;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值