线程池的原理

目录

1.创建线程池

1.第一种方式:ThreadPoolExecutor类

1.ThreadPoolExecutor类的源码

2.ThreadPoolExecutor类的源码的参数

2.1 int corePoolSize:

2.2 int maximumPoolSize:

2.3 long keepAliveTime:

2.4 TimeUnit unit:存活时间单位:

2.5 BlockingQueue workQueue:

2.6 ThreadFactory threadFactory:

2.7 RejectedExecutionHandler handler:

常用的拒绝策略:

2.第二种方式:Executors工具类

1.Executors工具类的源码

2.Executors工具类源码的方法

2.1 newFixedThreadPool(int nThreads):创建固定线程池

2.2 newSingleThreadExecutor():创建单线程

2.3 newCachedThreadPool():创建可缓存线程池

2.4 newScheduledThreadPool(int corePoolSize):创建定时执行线程池

3.创建线程池方法的选择

1.任务队列的分类

2. Executors工具类的方法中使用的任务队列

2.线程池执行过程


1.创建线程池

1.第一种方式:ThreadPoolExecutor类

1.ThreadPoolExecutor类的源码

概念:是线程池的实现类,使用类的构造器来创建线程

源码:

public ThreadPoolExecutor(
							  //核心线程数
			                  int corePoolSize,
							  //最大线程数
							  int maximumPoolSize,
							  //线程存活时间
							  long keepAliveTime,
							  //存活时间单位:通常是Seconds
							  TimeUnit unit,
							  //任务队列
							  BlockingQueue<Runnable> workQueue,
							  //线程工厂
							  ThreadFactory threadFactory,
							  //拒绝策略
							  RejectedExecutionHandler handler) {
		if (corePoolSize < 0 ||
				maximumPoolSize <= 0 ||
				maximumPoolSize < corePoolSize ||
				keepAliveTime < 0)
			throw new IllegalArgumentException();
		if (workQueue == null || threadFactory == null || handler == null)
			throw new NullPointerException();
		this.acc = System.getSecurityManager() == null ?
				null :
				AccessController.getContext();
		this.corePoolSize = corePoolSize;
		this.maximumPoolSize = maximumPoolSize;
		this.workQueue = workQueue;
		this.keepAliveTime = unit.toNanos(keepAliveTime);
		this.threadFactory = threadFactory;
		this.handler = handler;
	}

2.ThreadPoolExecutor类的源码的参数

2.1 int corePoolSize:

        核心线程数,代表了处理线程时的核心运行线程数量(任务队列此时是没有存满的)

2.2 int maximumPoolSize:

        最大线程数,当任务队列存满了,同时运行的线程数量大于核心线程数,此时代表的是最大线程数量

这二者的区别:一般任务队列没存满,就用corePoolSize;任务队列存满后仍有线程任务,此时就需要用到maximumPoolSize,创建非核心线程处理任务

2.3 long keepAliveTime:

        线程存活时间,线程未处理任务的最大存活时间,超过这个时间就回收线程

2.4 TimeUnit unit:存活时间单位:

        通常是keepAliveTime的单位,比如TimeUnit.Seconds

2.5 BlockingQueue<Runnable> workQueue:

        任务队列,当运行线程的数量达到corePoolSize,则将任务存放在任务队列中

2.6 ThreadFactory threadFactory:

        线程工厂,用来创建新线程

2.7 RejectedExecutionHandler handler:

        拒绝策略,当任务队列workQueue已满,且正在运行的线程数达到了最大线程数maximumPoolSize,此时需要对新任务根据策略进行处理;

常用的拒绝策略:

2.7.1 AbortPolicy:中止策略;直接抛出异常

2.7.2 DiscardPolicy:丢弃策略;将新任务丢弃

2.7.3 DiscardOldestPolicy:丢弃最旧策略;丢弃最旧的任务请求

2.7.4 CallerRunsPolicy:调用方运行策略;调用当前线程运行新任务
                              

2.第二种方式:Executors工具类

1.Executors工具类的源码

概念:是一个工具类,定义了许多创建线程池的方法

源码:Executors工具类中声明的方法有:

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


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

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

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

2.Executors工具类源码的方法

2.1 newFixedThreadPool(int nThreads):创建固定线程池

        处理任务时,先判断是否有空闲线程,没有则放到任务队列,有则直接执行

2.2 newSingleThreadExecutor():创建单线程

        处理任务时,判断该单线程是否空闲,不空闲则放到任务队列,空闲就直接执行

2.3 newCachedThreadPool():创建可缓存线程池

        处理任务时,若有空闲线程,则使用空闲线程处理任务;若没有空闲线程,则创建新的线程处理任务,处理完毕缓存到线程池

2.4 newScheduledThreadPool(int corePoolSize):创建定时执行线程池

        该线程池能够定期执行任务或者延迟执行任务;一般都不会用到

3.创建线程池方法的选择

        一般使用ThreadPoolExecutor类来创建线程池

原因:与任务队列有关

1.任务队列的分类

SynchronousQueue:同步队列(无界);不存储元素,队列直接提交给线程执行:

        若有空闲线程,则使用空闲线程来处理

        没有空闲线程,则新建一个线程来处理任务

存在问题:会创建大量线程,产生Out Of Memory错误
 
LinkedBlockingQueue:无界对列;当线程池线程数达到最大数量,新任务就会在队列中等待执行

存在问题:可能会造成队列无限膨胀
 
ArrayBlockingQueue:有界队列;有助于防止资源耗尽

存在问题:一旦达到上限,可能会造成新任务丢失

2. Executors工具类的方法中使用的任务队列

newFixedThreadPool:LinkedBlockingQueue;会造成队列无限膨胀

newSingleThreadExecutor:LinkedBlockingQueue;会造成队列无限膨胀

newCachedThreadPool:SynchonousQueue;会创建大量线程

newScheduledThreadPool:DelayedWorkQueue;队列存满后会自动扩容,造成队列无限膨胀

综上:由于Executors工具类的方法中使用的任务队列会产生种种资源浪费问题,通常采用ThreadPoolExecutor类来创建线程池

2.线程池执行过程

处理任务时:

  • 若当前运行的线程数小于核心线程数,则新建一个线程处理该任务;
  • 若当前运行的线程数大于等于核心线程数,但小于最大线程数,则将任务存放到任务队列
    • 若任务队列已满,但当前运行线程数小于最大线程数,则新建一个线程处理任务
      • 若任务队列已满,且当前运行线程数大于最大线程数,则根据拒绝策略处理该任务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值