关于Java中的线程池

关于线程池

今天总结一下线程池😘

Java中的线程池相当于把很多线程放到一个池子里,随用随取,避免频繁的创建和销毁线程造成的资源损耗和提高响应速度,而且线程池可以根据需要动态地调整线程数量,以适应不同的工作负载,从而提高系统的灵活性和性能

线程池参数

先讲一下面试爱问的7大线程池参数💕:

arduino 复制代码
 public ThreadPoolExecutor(int corePoolSize,
                           int maximumPoolSize,
                           long keepAliveTime,
                           TimeUnit unit,
                           BlockingQueue<Runnable> workQueue,
                           ThreadFactory threadFactory,
                           RejectedExecutionHandler handler) {...}
  • corePoolSize: 线程池中的核心线程数量,如果没有全局设置池内线程的过期时间,池内会维持此数量线程。
  • maximumPoolSize: 线程池中的最大线程数量,当核心线程都在运行任务,并且阻塞队列中任务数量已满,此时会创建非核心线程。
  • keepAliveTime & unit: 线程池中线程过期时间以及时间单位。
  • workQueue: 存放线程池内任务的阻塞队列,如 ArrayBlockingQueue、LinkedBlockingQueue...
  • threadFactory: 创建线程池中线程的线程工厂,可以在创建线程时初始化优先级、名称、守护状态...
  • handler: 当线程池中全部线程都在运行,阻塞队列也满的时候,会将添加的任务执行拒绝策略,JDK 线程池中实现了四种拒绝策略,默认 AbortPolicy,抛出异常。

简单来讲就是先找核心线程数,如果核心线程数满了,就进去阻塞队列,等着来找核心线程,如果队列都满了,那就使用非核心线程来处理,如果都超过最大线程数了,就使用拒绝策略具体处理

魔改一下?😎

如果我们想要线程池快速消费呢?

那看一下线程池消费的过程,有个排队去找核心线程数的过程,这个排队就造成时间浪费了

那么能不能改一下让请求来了发现核心线程数满了,直接去找非核心线程去执行,是不是相当于速度快了

Dubbo中的实现😶‍🌫️

其实Dubbo中早有其影子🙌🙌🙌

首先Dubbo中自定义了一个TaskQueue 阻塞队列扩展了LinkedBlockingQueue

scala 复制代码
 public class TaskQueue<R extends Runnable> extends LinkedBlockingQueue<Runnable> {
         ...
     // 队列中持有线程池的引用
     private EagerThreadPoolExecutor executor;
 ​
     public TaskQueue(int capacity) {
         super(capacity);
     }
 ​
     public void setExecutor(EagerThreadPoolExecutor exec) {
         executor = exec;
     }
 ​
     @Override
     public boolean offer(Runnable runnable) {
                 ...
         // 获取线程池中线程数
         int currentPoolThreadSize = executor.getPoolSize();
         // 如果有核心线程正在空闲,将任务加入阻塞队列,由核心线程进行处理任务
         if (executor.getSubmittedTaskCount() < currentPoolThreadSize) {
             return super.offer(runnable);
         }
 ​
         /**
          *【重点】当前线程池线程数量小于最大线程数
          * 返回false,根据线程池源码,会创建非核心线程
          */
         if (currentPoolThreadSize < executor.getMaximumPoolSize()) {
             return false;
         }
 ​
         // 如果当前线程池数量大于最大线程数,任务加入阻塞队列
         return super.offer(runnable);
     }
 }

慢慢来看😊,这段代码中,意思是线程来了先去找核心线程,如果核心满了,看是否小于最大线程数,小于的话,为了实现快速消费的目的,就直接失败,大于最大线程数的话,就说明当前要处理的线程比较多,就都放入阻塞队列慢慢消费

另一方面:

Dubbo中的EagerThreadPoolExecutor 封装了线程池,对原有的ThreadPoolExecutor类进行了扩展:

java 复制代码
 public class EagerThreadPoolExecutor extends ThreadPoolExecutor {
 ​
     /**
      * task count
      */
     private final AtomicInteger submittedTaskCount = new AtomicInteger(0);
 ​
     /**
      * @return current tasks which are executed
      */
     public int getSubmittedTaskCount() {
         return submittedTaskCount.get();
     }
 ​
     @Override
     protected void afterExecute(Runnable r, Throwable t) {
         submittedTaskCount.decrementAndGet();
     }
 ​
     @Override
     public void execute(Runnable command) {
         if (command == null) {
             throw new NullPointerException();
         }
         // do not increment in method beforeExecute!
         submittedTaskCount.incrementAndGet();
         try {
             super.execute(command);
         } catch (RejectedExecutionException rx) {
             // retry to offer the task into queue.
             final TaskQueue queue = (TaskQueue) super.getQueue();
             try {
                 if (!queue.retryOffer(command, 0, TimeUnit.MILLISECONDS)) {
                     submittedTaskCount.decrementAndGet();
                     throw new RejectedExecutionException("Queue capacity is full.", rx);
                 }
             } catch (InterruptedException x) {
                 submittedTaskCount.decrementAndGet();
                 throw new RejectedExecutionException(x);
             }
         } catch (Throwable t) {
             // decrease any way
             submittedTaskCount.decrementAndGet();
             throw t;
         }
     }
 }

我知道你很急,但是你先别急🙌🙌🙌

慢慢看,它主要是重写了其中的execute方法,它在里面定义了一个原子整数,用于记录已提交的任务数量

首先会对任务数量进行递增,然后尝试执行任务。如果任务执行被拒绝,会尝试将任务重新放入队列中。无论任务执行成功与否,已提交的任务数量都会递减

这样就能保证在高并发情况下 TaskQueue#offer(Runnable runnable) 做出逻辑处理

OK!完美,总的来说,不是很难💕💕💕

相关推荐
zjw_rp26 分钟前
Spring-AOP
java·后端·spring·spring-aop
TodoCoder1 小时前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
机器之心2 小时前
图学习新突破:一个统一框架连接空域和频域
人工智能·后端
.生产的驴3 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
顽疲3 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端
机器之心3 小时前
AAAI 2025|时间序列演进也是种扩散过程?基于移动自回归的时序扩散预测模型
人工智能·后端
hanglove_lucky4 小时前
本地摄像头视频流在html中打开
前端·后端·html
皓木.6 小时前
(自用)配置文件优先级、SpringBoot原理、Maven私服
java·spring boot·后端
i7i8i9com6 小时前
java 1.8+springboot文件上传+vue3+ts+antdv
java·spring boot·后端
秋意钟6 小时前
Spring框架处理时间类型格式
java·后端·spring