关于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!完美,总的来说,不是很难💕💕💕

相关推荐
NiNg_1_2343 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
Chrikk4 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*4 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue4 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man4 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
customer086 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
Yaml47 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
小码编匠8 小时前
一款 C# 编写的神经网络计算图框架
后端·神经网络·c#