线程池的使用和底层实现

2 篇文章 0 订阅
1 篇文章 0 订阅

什么是线程池

线程池是指在初始化一个多线程应用过程中创建的一个线程集合,该线程集合使得程序在执行任务时不再需要临时创建新的线程,而是可以直接调用线程池中的线程。线程池可以同时执行多个任务,如果任务队列已满,则新来的任务会排队等待,线程池的线程数量不会大于既定的最大值。

线程池的优点

  • 降低资源的消耗。重复利用已创建的线程,降低创建和销毁线程的资源消耗
  • 提高程序的响应效率。任务到达时,不再需要等待创建线程时间,直接调用即可。
  • 提高线程的可管理性

线程池的参数

  • corePoolSize:核心池的大小;在创建线程池后,默认情况下,线程池中没有任何线程池,而是等到任务到达时才创建线程去执行任务。除非调用prestartAllCoresThreads()或者prestartCoreThread()这两个方法预创建线程;即在没有任务到来之前就创建了corePoolSize个线程。当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中。
  • maximumPoolSize:最大线程数。表示线程池中最多能创建的线程数。
  • keepAliveTime:非核心线程闲置时的超时时长,超过这个时长会被回收,如果核心线程.allowCoreThreadTimeOut设置成了true,那么核心线程在闲置的情况下,也会被回收。
  • unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS          //天  
TimeUnit.HOURS         //小时  
TimeUnit.MINUTES       //分钟  
TimeUnit.SECONDS       //秒  
TimeUnit.MILLISECONDS  //毫秒 ,等于1∗10−3s
TimeUnit.MICROSECONDS  //微秒,等于1∗10−6s
TimeUnit.NANOSECONDS   //纳秒,等于1∗10−9s
  • workQueue:线程池中的任务队列,通过execute方法提交的runnable对象会存储在该队列中
  • allowCoreThreadTimeout:允许核心线程超时

下面说说系统常用的4种线程池的实现原理:

1.newSingleThreadExecutor() 

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务都是按照指定的顺序(FIFO,LIFO,优先级)执行。

2.newFixedThreadPool() 

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

3.newScheduledThreadPool(int corePoolSize) 

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
 public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
              new DelayedWorkQueue());
    }

固定核心线程,主要用于定时任务或者周期性任务。 

4.newCachedThreadPool() 

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

没有核心线程,不固定线程的数量,超时时长60秒,超过后会被回收,所以它的特性在空闲时,没有线程几乎是不占用内存的,适用于多量耗时少的任务。 
以上4种都是通过Executors 下面对应类型的方法来创建。

线程池饱和策略

1. Abort策略:默认策略,不执行此任务,而且直接抛出一个运行时异常,切记ThreadPoolExecutor.execute需要try catch,否则程序会直接退出。

2. CallerRuns策略:为调节机制,既不抛弃任务也不抛出异常,而是将某些任务回退到调用者。不会在线程池的线程中执行新的任务,而是在调用exector的线程中运行新的任务。

3. Discard策略:新提交的任务被抛弃,任务不执行。

4. DiscardOldest策略:当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务(抛弃下一个将被执行的任务),然后将被拒绝的任务添加到等待队列中,如果队列是一个优先队列,那么抛弃 最旧的策略就会抛弃优先级最高的任务,因此不要将两者在一起使用。

5. 用户自定义拒绝策略(最常用):实现RejectedExecutionHandler,并自己定义策略模式

/**
 * 循环,当队列有空位时,该任务进入队列,等待线程池处理
 */
public class TestRejectedExecutionHandler implements RejectedExecutionHandler {

	public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
		try {
			executor.getQueue().put(r);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值