线程池没那么“复杂”

线程池

使用好处

  1. 响应速度快
  2. 合理利用cpu和内存
  3. 统一管理线程资源

适用场合

  1. 服务器大量请求;
  2. 五个以上就可以使用线程池来管理;

线程池参数

在这里插入图片描述

线程池添加线程规则

  1. 核心线程数没满就创建线程执行任务;
  2. 如果核心线程数满了,就将新任务存入工作队列;
  3. 如果核心线程数和工作队列都满了(线程还未到最大线程数),就创建新的线程来执行任务;
  4. 如果线程达到最大线程数,执行拒绝策略;

线程池希望保持较少的线程数,并且只有在负载很大的情况下才增加它;

KeepAliveTime(最大空闲时间)

如果线程数大于corePoolSize,那么如果多余的线程空闲时间超过KeepAliveTime,就会被回收;

ThreadFactory(线程工厂)

新的线程是由ThreadFactory来创建的,默认使用Executors.defaultThreadFactory,优先级都为5;

WorkQueue(工作队列)

  • SynchronousQueue(直接交换,无法存储任务);
  • LinkedBlockingQueue(无界队列,如果处理速度跟不上任务提交会报OOM);
  • ArrayBlockingQueue(有界队列);

newFixedThreadPool(传入固定线程数)

传入核心线程数;

使用LinkedBlockingQueue,请求堆积占用大量内存,如果处理速度跟不上任务提交会报OOM

newSingleThreadExecutor(单线程)

核心线程数和最大线程数都是1

使用LinkedBlockingQueue,请求堆积占用大量内存;

CachedThreadPool(可缓存)

可缓存线程池;

无界线程池,具有自动回收多余线程功能;

核心线程数为0,最大线程数为Integer.MAX_VALUE(如果创建线程非常多会报OOM);

KeepAliveTime为60s,默认回收时间;

使用SynchronousQueue直接交换;

newScheduledThreadPool(支持定时以及周期执行任务)

可以调用一些定时执行任务的方法;

使用DelayedWorkQueue(延迟队列)

workStealingThreadPool(窃取)

子任务(递归场景);

窃取(执行完任务的线程会窃取未执行完任务线程的任务去执行);

线程池数量设置

CPU密集型:线程数=CPU核数+1;

I/O密集型:线程数=CPU核数*(1+平均等待时间/平均工作时间);

常见线程池参数

在这里插入图片描述

停止线程池

  1. shutdown(将已有的任务执行完,新来的任务拒绝);
  2. isShutdown(返回boolean,是否进入停止状态);
  3. isTerminated(返回boolean,判断任务是否执行完毕);
  4. awaitTermination(返回boolean,判断在指定时间内,任务是否执行完毕);
  5. shutdownNow(立刻关闭线程池,返回工作队列列表List );

拒绝策略

  • AbortPolicy(抛出异常);
  • DiscardPolicy(丢弃);
  • DiscardOldestPolicy(丢弃最老的任务);
  • CallerRunsPolicy(提交任务线程去执行);

钩子方法(线程池执行前后调用)

重写beforeExecute方法;

线程池组成部分

  • 线程池管理器
  • 工作线程
  • 任务队列
  • 任务Task

Executor(Interface)——ExecutorService(Interface)——AbstractExectorService——ThreadPoolExecutor

Executors(工具类,可以创建线程池);

线程复用(相同线程执行不同的任务)

如果当前线程数<核心线程数,那么就addWork,从队列中取task,然后执行runWorker,调用task.run执行任务;

线程池状态(5种)

RUNNING:接受新任务,处理队列任务;

SHUTDOWN:不接受新任务,处理队列任务;

STOP:不接受新任务,也不处理队列任务,中断正在执行的任务;

TIDYING:所有任务都已终止,运行terminate*钩子方法;

TERMINATED:线程池不能重新启动;

execute源码

//线程池执行线程  传入runnable
public void execute(Runnable command) {
  			//如果传入线程为null 抛出异常
        if (command == null)
            throw new NullPointerException();
  //取到线程数
 int c = ctl.get();
  //线程数<corepoolsize
    if (workerCountOf(c) < corePoolSize) {
      //添加新线程执行任务   传入true判断增加线程数是否小于corePoolSize
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
  //线程池是运行状态,线程数>corePoolSize   并且队列没满
    if (isRunning(c) && workQueue.offer(command)) {
      //检查线程池状态
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
          //没有运行就拒绝策略
            reject(command);
      //检查线程池线程数量,如果是0,就创建新线程
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
  //已经达到maxPoolSize了
    else if (!addWorker(command, false))
      //拒绝策略
        reject(command);
}

线程池使用Tips:

  • 避免任务堆积;
  • 避免线程过度增加;
  • 排除线程泄露(执行完毕,线程无法回收);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值