Java多线程实战-从零手搓一个简易线程池(四)线程池生命周期状态流转实现

🏷️个人主页:牵着猫散步的鼠鼠 

🏷️系列专栏:Java全栈-专栏

🏷️本系列源码仓库:多线程并发编程学习的多个代码片段(github)

🏷️个人学习笔记,若有缺误,欢迎评论区指正 

✨️本系列源码均已上传仓库 1321928757/Concurrent-MulThread-Demo(github.com)✨️ 

(本章节可参考liushijie-240409-lifecycle分支)

1.前言

在前面几篇文章中,我们已经实现了线程池的核心功能:任务队列、执行逻辑以及线程管理。本次我们将继续扩展补充线程池的功能,为线程池添加生命周期管理。

往期文章传送门:
Java多线程实战-从零手搓一个简易线程池(一)定义任务等待队列-CSDN博客

Java多线程实战-从零手搓一个简易线程池(二)线程池与拒绝策略实现-CSDN博客

Java多线程实战-从零手搓一个简易线程池(三)线程工厂,核心线程与非核心线程逻辑实现-CSDN博客

2.为什么要加入生命周期

通过引入生命周期,我们能够更加灵活地管理和控制线程的创建、运行和销毁过程。可以更好地处理资源分配、任务调度和系统稳定性等方面的问题。

2.1.生命周期的主要作用包括:

  1. 资源管理:线程池中的线程是一种昂贵的资源,通过引入生命周期,可以确保线程在适当的时机被创建和销毁,避免资源的浪费。

  2. 系统稳定性:线程池生命周期的管理可以帮助我们避免因线程过多或过少而导致的系统不稳定问题。通过合理地控制线程的数量,可以确保系统在处理高并发任务时仍能保持稳定运行。

  3. 任务调度:线程池生命周期的管理可以帮助我们更好地进行任务调度,确保任务能够按照预期的方式执行。例如,我们可以通过设置线程池的最大线程数和任务队列长度等参数,来控制任务的执行顺序和并发度。

  4. 系统扩展性:通过引入生命周期,我们可以为线程池添加更多的功能和特性,如线程池监控、任务统计等。这些功能和特性可以帮助我们更好地了解线程池的运行状况,从而对其进行优化和扩展。

2.2.线程池的状态分类:

线程池的状态一共有五种,分别是RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED;

  1. RUNNING,表示可接受新任务,且可执行队列中的任务;
  2. SHUTDOWN,表示不接受新任务,但可执行队列中的任务;
  3. STOP,表示不接受新任务,且不再执行队列中的任务,且中断正在执行的任务;
  4. TIDYING,所有任务已经中止,且工作线程数量为0,最后变迁到这个状态的线程将要执行terminated()钩子方法,只会有一个线程执行这个方法;
  5. TERMINATED,中止状态,已经执行完terminated()钩子方法;

为了简化过程,我们这里就简单实现三种状态RUNNING, SHUTDOWN, STOP

3.设计思路

对于线程池的状态管理,我们这里实现两个最常用的方法,shutdown和shutdownNow,这两个方法都会关闭线程池,前者为优雅关闭,会等待全部任务执行完成后关闭线程池,而后者是立刻关闭,他会中断所有正在运行的线程,不管任务有没有执行完成。

我们简易线程池的状态流转如下:

当线程池初始化创建时,默认为Running状态,我们调用shutdown 

4.代码实现

4.1.定义状态相关字段

我们在ThreadPool对象中定义AtomicInteger 原子类作为线程池状态

    /** 线程池状态常量*/private static final int RUNNING    = 1;private static final int SHUTDOWN   = 2;private static final int STOP       = 3;private static final int TIDYING    = 4;private static final int TERMINATED = 5;/** 线程池当前状态*/private final AtomicInteger state = new AtomicInteger(RUNNING);

4.2.修改excute方法

我们添加了一个状态判断,如果线程池状态为SHUTDOWN以上,我们直接拒绝任务

    public boolean isShutdown() {return state.get() >= SHUTDOWN;}
public void execute(Runnable task){if(task == null){throw new NullPointerException("传递的Runnable任务为Null");}// 1.如果线程池状态为SHUTDOWN以上,不再接受任务,直接触发拒绝策略if(isShutdown()){reject(task);}// 2.如果当前线程数小于核心线程,直接创建线程去运行if(threadTotalNums.get() < corePoolSize){if(addWorker(task, true)) return;}// 3.线程数大于核心线程,我们就将任务加入等待队列if(workQueue.offer(task)){return;}// 4.队列满了,尝试创建非核心线程,如果失败就触发拒绝策略else if(!addWorker(task, false)){reject(task);}}

4.2.修改addWorker方法

我们在addWorker方法添加工作线程前,加入线程池状态的判断,当线程池状态不为Running(大于Running)时,我们直接返回false,不再添加工作线程

c == SHUTDOWN && !workQueue.isEmpty()
这个条件是指当线程池为SHUTDOWN状态,但workQueue不为空,此时我们可能还需要创建新的线程来加速处理速度,所以这种情况下我们不应该返回false

public Boolean addWorker(Runnable firstTask, Boolean isCore){if(firstTask == null) {throw new NullPointerException();}// 1.生命周期检查,不在RUNNING状态下不继续添加工作线程(但是可能存在刚关闭线程池的情况,此时状态为shutdown,如果任务队列不为空,我们依旧允许创建线程,来加快任务处理)final int c = state.get();if (c > RUNNING && !(c == SHUTDOWN && !workQueue.isEmpty())) {return false;}// 2.根据当前线程池和isCore条件判断是否需要创建int wc = threadTotalNums.get();if (wc >= (isCore ? corePoolSize : maximumPoolSize))return false;// 3.创建线程,并添加到线程集合中Worker worker = new Worker(firstTask);Thread t = worker.thread;if(t != null){synchronized (workerSet){workerSet.add(worker);threadTotalNums.getAndIncrement();}t.start();return true;}return false;}

4.3.修改getTask方法

当线程池状态为SHUTDOWN 以上时,并且满足状态大于Stop或者任务队列为空两者条件之一时,我们停止获取任务,直接返回null

shutdown状态下只是不接受新任务了,但是队列中原有的任务还是会执行,而stop状态下是队列中的任务也不执行了

4.4定义shutdown,shutdownNow等状态管理方法

 shutdown方法:我们直接调用原子类的CAS操作来切换状态

    public void shutdown() {// 如果为if (state.compareAndSet(RUNNING, SHUTDOWN)) {log.info("线程池正在关闭");tryTerminate(); // 尝试转换到TERMINATED状态}}

shotdownNow方法:我们遍历线程集合,中断所有运行中的线程,这里需要注意异常处理

public void shutdownNow() {if (state.compareAndSet(RUNNING, STOP)) {try {log.info("线程池立即关闭,尝试中断所有线程");// 中断所有正在运行的线程synchronized (workerSet){for (Worker worker : workerSet) {worker.thread.interrupt();}}} finally {state.set(TIDYING);// 在此处执行清理工作transitionToTerminated();}}}

 tryTerminate与transitionToTerminated方法

    private void tryTerminate() {if ((state.get() == SHUTDOWN || state.get() == STOP) && workQueue.isEmpty() && workerSet.isEmpty()) {if (state.compareAndSet(SHUTDOWN, TIDYING) || state.compareAndSet(STOP, TIDYING)) {// 在此处执行清理工作transitionToTerminated();log.info("线程池已终止");}}}private void transitionToTerminated() {state.set(TERMINATED);// 这里可以通知等待线程池终止的线程}

 在线程回收时调用tryTerminate方法,尝试转换线程池状态

// 2.跳出循环,说明取任务超过了最大等待时间,线程歇菜休息吧synchronized (workerSet){workerSet.remove(this);threadTotalNums.decrementAndGet(); //计数扣减}log.info("工作线程====》线程{}已被回收,当前线程数:{}", Thread.currentThread(), threadTotalNums.get());tryTerminate(); // 尝试转换线程池状态

5.测试 

我们设置线程池不允许回收核心线程,然后在添加任务后直接调用shutdownNow立即停止线程

    public static void main(String[] args){ThreadPool threadPool = new ThreadPool(new WorkQueue<>(5), 2, 5,5L, TimeUnit.SECONDS,(queue, task) -> {log.info("拒绝策略====》拒绝策略触发,直接丢弃当前任务");}, new DefaultThreadFactory());threadPool.setAllowCoreThreadTimeOut(false);for (int i = 0; i < 15; i++) {int finalI = i;threadPool.execute(() -> {log.info("执行任务{}------->当前执行线程为{}" , finalI, Thread.currentThread().toString());});}threadPool.shutdownNow();}

运行结果如下,可以看到任务并没有全部执行完,全部线程就被回收了 

---------------线程池创建成功--------------
最大核心线程数:2
最大总线程数:5
线程最大空闲时间:5
空闲时间单位:SECONDS
allowCoreThreadTimeOut:false
----------------------------------------
21:11:30.648 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.648 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.648 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.649 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.649 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-1,5,main]开始运行
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.MainTest - 执行任务0------->当前执行线程为Thread[pool-1-thread-1,5,main]
21:11:30.649 [pool-1-thread-2] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-2,5,main]开始运行
21:11:30.649 [pool-1-thread-2] INFO com.luckysj.threadpool.MainTest - 执行任务1------->当前执行线程为Thread[pool-1-thread-2,5,main]
21:11:30.649 [pool-1-thread-4] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-4,5,main]开始运行
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-1,5,main]任务拿取成功
21:11:30.649 [pool-1-thread-3] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-3,5,main]开始运行
21:11:30.649 [pool-1-thread-4] INFO com.luckysj.threadpool.MainTest - 执行任务8------->当前执行线程为Thread[pool-1-thread-4,5,main]
21:11:30.649 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.MainTest - 执行任务2------->当前执行线程为Thread[pool-1-thread-1,5,main]
21:11:30.649 [pool-1-thread-3] INFO com.luckysj.threadpool.MainTest - 执行任务7------->当前执行线程为Thread[pool-1-thread-3,5,main]
21:11:30.649 [pool-1-thread-2] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-2,5,main]任务拿取成功
21:11:30.649 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.649 [pool-1-thread-2] INFO com.luckysj.threadpool.MainTest - 执行任务3------->当前执行线程为Thread[pool-1-thread-2,5,main]
21:11:30.649 [main] INFO com.luckysj.threadpool.MainTest - 拒绝策略====》拒绝策略触发,直接丢弃当前任务
21:11:30.649 [pool-1-thread-4] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-4,5,main]任务拿取成功
21:11:30.649 [pool-1-thread-4] INFO com.luckysj.threadpool.MainTest - 执行任务4------->当前执行线程为Thread[pool-1-thread-4,5,main]
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-1,5,main]任务拿取成功
21:11:30.649 [pool-1-thread-5] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-5,5,main]开始运行
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.MainTest - 执行任务5------->当前执行线程为Thread[pool-1-thread-1,5,main]
21:11:30.649 [pool-1-thread-3] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-3,5,main]任务拿取成功
21:11:30.649 [pool-1-thread-5] INFO com.luckysj.threadpool.MainTest - 执行任务10------->当前执行线程为Thread[pool-1-thread-5,5,main]
21:11:30.649 [pool-1-thread-5] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-5,5,main]任务拿取成功
21:11:30.649 [pool-1-thread-3] INFO com.luckysj.threadpool.MainTest - 执行任务6------->当前执行线程为Thread[pool-1-thread-3,5,main]
21:11:30.649 [pool-1-thread-5] INFO com.luckysj.threadpool.MainTest - 执行任务9------->当前执行线程为Thread[pool-1-thread-5,5,main]
21:11:30.649 [pool-1-thread-3] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-3,5,main]任务拿取成功
21:11:30.649 [pool-1-thread-3] INFO com.luckysj.threadpool.MainTest - 执行任务11------->当前执行线程为Thread[pool-1-thread-3,5,main]
21:11:30.649 [pool-1-thread-2] DEBUG com.luckysj.threadpool.core.WorkQueue - 等待队列====》Thread[pool-1-thread-2,5,main]线程等待获取任务
21:11:30.649 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.649 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:11:30.649 [main] INFO com.luckysj.threadpool.core.ThreadPool - 线程池立即关闭,尝试中断所有线程
21:11:30.649 [pool-1-thread-4] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-4,5,main]任务拿取成功
21:11:30.649 [pool-1-thread-4] INFO com.luckysj.threadpool.MainTest - 执行任务13------->当前执行线程为Thread[pool-1-thread-4,5,main]
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-1,5,main]任务拿取成功
21:11:30.649 [main] INFO com.luckysj.threadpool.core.ThreadPool - 线程池已终止
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.MainTest - 执行任务14------->当前执行线程为Thread[pool-1-thread-1,5,main]
21:11:30.649 [pool-1-thread-5] DEBUG com.luckysj.threadpool.core.WorkQueue - 等待队列====》Thread[pool-1-thread-5,5,main]线程等待获取任务
21:11:30.649 [pool-1-thread-4] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-4,5,main]已被回收,当前线程数:4
21:11:30.649 [pool-1-thread-1] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-1,5,main]已被回收,当前线程数:3
21:11:30.649 [pool-1-thread-3] DEBUG com.luckysj.threadpool.core.WorkQueue - 等待队列====》Thread[pool-1-thread-3,5,main]线程等待获取任务
21:11:30.649 [pool-1-thread-5] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-5,5,main]已被回收,当前线程数:2
21:11:30.649 [pool-1-thread-3] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-3,5,main]已被回收,当前线程数:1
21:11:30.650 [pool-1-thread-2] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-2,5,main]已被回收,当前线程数:0

我们将shutdownNow方法改为shutdown,运行结果如下,可以看到全部任务执行完成后才开始回收核心线程

21:12:08.248 [main] INFO com.luckysj.threadpool.core.ThreadPool - 
---------------线程池创建成功--------------
最大核心线程数:2
最大总线程数:5
线程最大空闲时间:5
空闲时间单位:SECONDS
allowCoreThreadTimeOut:false
----------------------------------------
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [pool-1-thread-1] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-1,5,main]开始运行
21:12:08.252 [pool-1-thread-2] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-2,5,main]开始运行
21:12:08.252 [pool-1-thread-1] INFO com.luckysj.threadpool.MainTest - 执行任务0------->当前执行线程为Thread[pool-1-thread-1,5,main]
21:12:08.252 [pool-1-thread-2] INFO com.luckysj.threadpool.MainTest - 执行任务1------->当前执行线程为Thread[pool-1-thread-2,5,main]
21:12:08.252 [pool-1-thread-1] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-1,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-1] INFO com.luckysj.threadpool.MainTest - 执行任务2------->当前执行线程为Thread[pool-1-thread-1,5,main]
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [pool-1-thread-3] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-3,5,main]开始运行
21:12:08.252 [pool-1-thread-3] INFO com.luckysj.threadpool.MainTest - 执行任务7------->当前执行线程为Thread[pool-1-thread-3,5,main]
21:12:08.252 [pool-1-thread-5] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-5,5,main]开始运行
21:12:08.252 [pool-1-thread-4] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》工作线程Thread[pool-1-thread-4,5,main]开始运行
21:12:08.252 [pool-1-thread-5] INFO com.luckysj.threadpool.MainTest - 执行任务9------->当前执行线程为Thread[pool-1-thread-5,5,main]
21:12:08.252 [pool-1-thread-4] INFO com.luckysj.threadpool.MainTest - 执行任务8------->当前执行线程为Thread[pool-1-thread-4,5,main]
21:12:08.252 [pool-1-thread-3] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-3,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-3] INFO com.luckysj.threadpool.MainTest - 执行任务3------->当前执行线程为Thread[pool-1-thread-3,5,main]
21:12:08.252 [pool-1-thread-2] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-2,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-2] INFO com.luckysj.threadpool.MainTest - 执行任务4------->当前执行线程为Thread[pool-1-thread-2,5,main]
21:12:08.252 [pool-1-thread-1] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-1,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-1] INFO com.luckysj.threadpool.MainTest - 执行任务5------->当前执行线程为Thread[pool-1-thread-1,5,main]
21:12:08.252 [pool-1-thread-5] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-5,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-5] INFO com.luckysj.threadpool.MainTest - 执行任务6------->当前执行线程为Thread[pool-1-thread-5,5,main]
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [pool-1-thread-4] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-4,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-3] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-3,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-4] INFO com.luckysj.threadpool.MainTest - 执行任务10------->当前执行线程为Thread[pool-1-thread-4,5,main]
21:12:08.252 [pool-1-thread-3] INFO com.luckysj.threadpool.MainTest - 执行任务11------->当前执行线程为Thread[pool-1-thread-3,5,main]
21:12:08.252 [pool-1-thread-2] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-2,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-2] INFO com.luckysj.threadpool.MainTest - 执行任务12------->当前执行线程为Thread[pool-1-thread-2,5,main]
21:12:08.252 [pool-1-thread-1] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-1,5,main]任务拿取成功
21:12:08.252 [pool-1-thread-1] INFO com.luckysj.threadpool.MainTest - 执行任务13------->当前执行线程为Thread[pool-1-thread-1,5,main]
21:12:08.252 [pool-1-thread-5] DEBUG com.luckysj.threadpool.core.WorkQueue - 等待队列====》Thread[pool-1-thread-5,5,main]线程等待获取任务
21:12:08.252 [main] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》任务添加成功
21:12:08.252 [main] INFO com.luckysj.threadpool.core.ThreadPool - 线程池正在关闭
21:12:08.252 [pool-1-thread-4] INFO com.luckysj.threadpool.core.WorkQueue - 等待队列====》线程Thread[pool-1-thread-4,5,main]任务拿取成功
21:12:08.253 [pool-1-thread-4] INFO com.luckysj.threadpool.MainTest - 执行任务14------->当前执行线程为Thread[pool-1-thread-4,5,main]
21:12:08.253 [pool-1-thread-3] DEBUG com.luckysj.threadpool.core.WorkQueue - 等待队列====》Thread[pool-1-thread-3,5,main]线程等待获取任务
21:12:08.253 [pool-1-thread-2] DEBUG com.luckysj.threadpool.core.WorkQueue - 等待队列====》Thread[pool-1-thread-2,5,main]线程等待获取任务
21:12:08.253 [pool-1-thread-4] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-4,5,main]已被回收,当前线程数:4
21:12:08.253 [pool-1-thread-1] DEBUG com.luckysj.threadpool.core.WorkQueue - 等待队列====》Thread[pool-1-thread-1,5,main]线程等待获取任务
21:12:08.253 [pool-1-thread-5] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-5,5,main]已被回收,当前线程数:3
21:12:08.253 [pool-1-thread-5] INFO com.luckysj.threadpool.core.ThreadPool - 线程池已终止
21:12:08.253 [pool-1-thread-1] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-1,5,main]已被回收,当前线程数:0
21:12:08.253 [pool-1-thread-2] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-2,5,main]已被回收,当前线程数:1
21:12:08.253 [pool-1-thread-3] INFO com.luckysj.threadpool.core.ThreadPool - 工作线程====》线程Thread[pool-1-thread-3,5,main]已被回收,当前线程数:2

6.总结

本章节我们简单实现了线程池内部状态的流转,这个实现是一个非常基础的版本,方便提供小伙伴们学习和思考,如果有什么疑问或者建议欢迎评论区指出,我们下次再见,咕咕咕(又可以鸽几天了)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/803333.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nexus设置s3存储

问题 因为我的nexus是安装在EC2上面&#xff0c;需要利用s3的存储能力&#xff0c;为nexus提供存储服务。 步骤 准备s3桶 输入桶名&#xff0c;创建s3桶&#xff0c;如下图&#xff1a; 创建桶读写策略 具体内容如下&#xff1a; {"Version": "2012-10-1…

c++之代码编译问题

为什么头文件不是编译的对象 1、头文件与包含指令(#include) 那些没有被项目中任何源文件包含的头文件&#xff0c;编译器是不去理会它的&#xff0c;不管它有没有语法错误&#xff0c;也不管它是否已添加到项目中。 2、包含指令的执行 包含指令是一种预编译指令&#xff0c;它…

如何区别进化和演化

在生物学中&#xff0c;"进化"和"演化"这两个词通常可以互换使用&#xff0c;它们都指的是生物种群随时间推移而发生的遗传变化。然而&#xff0c;在某些语境中&#xff0c;这两个词可能会有细微的差别&#xff1a; 进化&#xff08;Evolution&#xff09;…

[翻译] 在 CI 或测试环境中使用 Docker-in-Docker,三思而后行

发布日期&#xff1a;2024-04-08 18:01:01 原文地址&#xff1a;Using Docker-in-Docker for your CI or testing environment? Think twice. Docker-in-Docker 的主要目的是帮助 Docker 本身的开发。许多人使用它来运行 CI&#xff08;例如使用 Jenkins&#xff09;&#xf…

[NKCTF2024]-PWN:leak解析(中国剩余定理泄露libc地址,汇编覆盖返回地址)

查看保护 查看ida 先放exp 完整exp&#xff1a; from pwn import* from sympy.ntheory.modular import crt context(log_leveldebug,archamd64)while True:pprocess(./leak)ps[101,103,107,109,113,127]p.sendafter(bsecret\n,bytes(ps))cs[0]*6for i in range(6):cs[i]u32(p…

Java 基于微信小程序的校园请教小程序的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、10年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447…

SpringBoot整合Spring Data JPA

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉🍎个人主页:Leo的博客💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容: SpringBoot整合Spring Data JPA 📚个人知识库: Leo知识库,欢迎大家访问 1.…

淘宝销量API商品详情页原数据APP接口测试㊣

淘宝/天猫获得淘宝app商品详情原数据 API 返回值说明 item_get_app-获得淘宝app商品详情原数据 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地…

Java-StringBuilder容器

一、基础用法 1.创建对象 StringBuilder sbnew StringBuilder(); 2.添加元素 可以添加整型、浮点型、字符串等。 sb.append(1); sb.append(2.3); sb.append(true); 3.反转 sb.reverse(); 4.获取长度 int len sb.length(); 5.转变成字符串 tring strsb.toString(); …

Python学习笔记11 - 列表

1. 列表的创建与删除 2. 列表的查询操作 3. 列表的增、删、改操作 4. 列表元素的排序 5. 列表生成式

利用IP地址判断羊毛用户:IP数据云提供IP风险画像

在当今数字化社会&#xff0c;互联网已经成为人们日常生活和商业活动中不可或缺的一部分。然而&#xff0c;随着网络的普及&#xff0c;网络欺诈行为也日益猖獗&#xff0c;其中包括了羊毛党这一群体。羊毛党指的是利用各种手段获取利益、奖励或者优惠而频繁刷取优惠券、注册账…

png转换成jpg格式?这几种方法很简单

在发送电子邮件时&#xff0c;附件的大小是一个重要的考虑因素。将PNG图像转换为jpg格式可以减小文件大小&#xff0c;减少附件的传输时间和存储空间占用。这对于商务邮件、个人邮件或邮件营销活动中的图片附件都非常有用&#xff0c;下面就介绍几个可以快速完成图片转格式的方…

Docker容器与虚拟化技术:OpenEuler 部署 Prometheus 与 Grafana

目录 一、实验 1.环境 2.OpenEuler 部署 Prometheus 3.OpenEuler 部署 Grafana 4.使用cpolar内网穿透 二、问题 1.拉取镜像失败 2.如何导入Grafana监控模板&#xff08;ES&#xff09; 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统架构版本IP备注…

Scrapy框架spider类异常处理

说明&#xff1a;仅供学习使用&#xff0c;请勿用于非法用途&#xff0c;若有侵权&#xff0c;请联系博主删除 作者&#xff1a;zhu6201976 一、捕获Request所有网络相关异常 在spider类中&#xff0c;我们构造Request对象或FormRequest对象时&#xff0c;可传递参数errback回调…

BugKu:Simple SSTI

1.进入此题 2.查看源代码 可以知道要传入一个名为flag的参数&#xff0c;又说我们经常设置一个secret_key 3.flask模版注入 /?flag{{config.SECRET_KEY}} 4.学有所思 4.1 什么是flask&#xff1f; flask是用python编写的一个轻量web开发框架 4.2 SSTI成因&#xff08;SST…

【数据结构与算法】:堆排序和选择排序

1. 堆排序 堆排序是一种比较复杂的排序算法&#xff0c;因为它的流程比较多&#xff0c;理解起来不会像冒泡排序和选择排序那样直观。 1.1 堆的结构 要理解堆排序&#xff0c;首先要理解堆。堆的逻辑结构是一棵完全二叉树&#xff0c;物理结构是一个数组。 (如果不知道什么是…

链表的中间结点——每日一题

题目链接&#xff1a; OJ链接 题目&#xff1a; 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&…

【架构师】-- 成长路线图

成长为软件架构师不是一件容易的事&#xff0c;这篇文章列举了架构师需要学习的技术储备&#xff0c;给出了成为软件架构师的路线图&#xff0c;帮助有志于在架构领域成长的同学可以明确学习的方向。原文&#xff1a;Master Plan for becoming a Software Architect[1] 软件架…

【优选算法专栏】专题十八:BFS解决拓扑排序(一)

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…

shamrockcms代码审计-啥也没有

shamrockcms 环境搭建 使用阿里源&#xff0c;创建数据库&#xff0c;运行shamrockcms.sql文件&#xff0c;将configure.properties中的jdbc修改为自己本地或者其他ip数据库连接&#xff0c;并且将ueditor.config.json中的master修改为localhost或者其他自己设置的ip 危险组件…