您的位置:首页 > 新闻 > 资讯 > java干货 线程池的分析和使用

java干货 线程池的分析和使用

2025/8/20 5:54:57 来源:https://blog.csdn.net/qq_51305563/article/details/139816282  浏览:    关键词:java干货 线程池的分析和使用

文章目录

    • 一、了解线程池
      • 1.1 什么是线程池
      • 1.2 为什么需要线程池
    • 二、四种线程池的使用
      • 2.1 newFixedThreadPool
      • 2.2 newCachedThreadPool
      • 2.3 newSingleThreadExecutor
      • 2.4 newScheduledThreadPool
    • 三、自定义线程池
      • 3.1 线程池七大核心参数
      • 3.2 线程池内部处理逻辑

一、了解线程池

1.1 什么是线程池

线程池就是一个装有多个线程的容器,我们不需要关心线程的创建,在需要时从线程池获取线程来执行即可。线程池提前创建和维护了一定数量的线程,避免线程频繁创建和销毁带来的性能损耗,同时能提高响应速度。

1.2 为什么需要线程池

我们需要一个线程来执行任务,直接 new 一个不就好了吗?确实是这样,写个demo直接创建线程就好,没必要线程池。但是在并发环境下需要创建多个线程来执行任务,每个线程执行的时间都很短,频繁的创建和销毁线程会耗费时间,因此需要线程池

二、四种线程池的使用

2.1 newFixedThreadPool

创建固定线程数量的线程池

  • newFixedThreadPool(int nThreads) 源码
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}
  • 实际调用 ThreadPoolExecutor,七大参数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}
  • 特点

    • 每个线程都是核心线程
    • 使用默认的线程工厂
    • 使用默认的拒绝策略
  • 使用

class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}}
}
public class Demo12 {public static void main(String[] args) {TaskRunnable taskRunnable = new TaskRunnable();ExecutorService executorService = Executors.newFixedThreadPool(3);for (int i = 0; i < 8; i++) {executorService.submit(taskRunnable);}}
}
pool-1-thread-2 售出第5张票
pool-1-thread-1 售出第4张票
pool-1-thread-3 售出第3张票
pool-1-thread-3 售出第2张票
pool-1-thread-3 售出第1张票
pool-1-thread-1没票了
pool-1-thread-2没票了
pool-1-thread-3没票了

分析:提交八个任务,由三个线程完成。

2.2 newCachedThreadPool

只要有任务需要处理,线程池可以无限制地创建新线程,如果有空闲的线程可以复用,则不会创建新线程。

  • newCachedThreadPool() 源码
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}
  • 实际调用 ThreadPoolExecutor 七大参数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}
  • 特点

    • 无核心线程
    • 根据需要动态扩缩容
    • 默认情况下,空闲线程的存活时间为 60 秒。如果线程在 60 秒内没有被使用,将被终止并从缓存中移除
  • 使用

class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}}
}
public class Demo12 {public static void main(String[] args) throws InterruptedException {TaskRunnable taskRunnable = new TaskRunnable();ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 10; i++) {executorService.submit(taskRunnable);}Thread.sleep(2000);System.out.println("-----------------------------继续提交-----------------------------------");for (int i = 0; i < 15; i++) {executorService.submit(taskRunnable);}}
}
pool-1-thread-3 售出第5张票
pool-1-thread-10 售出第4张票
pool-1-thread-9 售出第3张票
pool-1-thread-8 售出第2张票
pool-1-thread-7 售出第1张票
pool-1-thread-6没票了
pool-1-thread-2没票了
pool-1-thread-4没票了
pool-1-thread-5没票了
pool-1-thread-1没票了
-----------------------------继续提交-----------------------------------
pool-1-thread-7没票了
pool-1-thread-1没票了
pool-1-thread-6没票了
pool-1-thread-7没票了
pool-1-thread-9没票了
pool-1-thread-3没票了
pool-1-thread-8没票了
pool-1-thread-2没票了
pool-1-thread-12没票了
pool-1-thread-10没票了
pool-1-thread-4没票了
pool-1-thread-7没票了
pool-1-thread-11没票了
pool-1-thread-1没票了
pool-1-thread-5没票了

分析:可以发现提交十个任务,就创建了十个线程。在继续提交十五个任务时,会复用之前的十个线程,由于线程不够,继续创建了第十一和第十二个线程。

2.3 newSingleThreadExecutor

线程池中只有一个线程

  • newSingleThreadExecutor() 源码
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}
  • 实际调用 ThreadPoolExecutor 七大参数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}
  • 特点

    • 只有一个线程,该线程也是核心线程
    • 适用于同步场景
  • 使用

class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}}
}
public class Demo12 {public static void main(String[] args) throws InterruptedException {TaskRunnable taskRunnable = new TaskRunnable();ExecutorService executorService = Executors.newSingleThreadExecutor();for (int i = 0; i < 10; i++) {executorService.submit(taskRunnable);}}
}
pool-1-thread-1 售出第5张票
pool-1-thread-1 售出第4张票
pool-1-thread-1 售出第3张票
pool-1-thread-1 售出第2张票
pool-1-thread-1 售出第1张票
pool-1-thread-1没票了
pool-1-thread-1没票了
pool-1-thread-1没票了
pool-1-thread-1没票了
pool-1-thread-1没票了

分析:可以看出只有一个线程在执行任务,是串行

2.4 newScheduledThreadPool

延迟执行、定时执行

  • newScheduledThreadPool(核心线程数) 源码
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);}
  • 实际调用 ScheduledThreadPoolExecutor(int corePoolSize)
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue());}
  • 使用
class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}}
}
public class Demo12 {public static void main(String[] args) throws InterruptedException {TaskRunnable taskRunnable = new TaskRunnable();ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);for (int i = 0; i < 10; i++) {scheduledExecutorService.schedule(taskRunnable,3, TimeUnit.SECONDS);}}
}

分析:延迟,3 秒后执行。

  • scheduleAtFixedRate,1 秒后执行,每两秒执行一次
scheduledExecutorService.scheduleAtFixedRate(taskRunnable,1,2,TimeUnit.SECONDS);
  • 初始延迟为 0 秒。每次任务执行完成后,等待 2 秒再开始下一次执行。任务模拟执行时间为 2 秒。
scheduledExecutorService.scheduleWithFixedDelay(taskRunnable,0,2,TimeUnit.SECONDS);

-shutdown() :线程池不再接受新任务,但会继续执行已经提交的任务,直到所有任务执行完毕。

  • awaitTermination(2,TimeUnit.SECONDS) 判断2 秒内是否能完成全部任务

三、自定义线程池

3.1 线程池七大核心参数

  • 源码
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,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.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}

参数说明

  • 1.corePoolSize :核心线程数
  • 2.maximumPoolSize:最大线程数(核心线程数 + 核心线程数)
  • 3.keepAliveTime :非核心线程空闲时间,没有任务处理空闲超过该时间,线程会处于终止状态
  • 4.TimeUnit : 空闲时间单位
  • 5.BlockingQueue workQueue :任务队列
  • 6.ThreadFactory :线程工厂
  • 7.RejectedExecutionHandler :拒绝策略

3.2 线程池内部处理逻辑

三问:

  • 先问核心线程还够不够用
  • 再问任务队列是否已满
  • 最后问是否已达到最大线程数
  • 如果任务队列已满,那么创建非核心线程
  • 如果任务队列已满,同时达到最大线程数,再添加任务,则执行拒绝策略。

创建和使用自定义线程池

class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}try {Thread.sleep(1000); // 模拟做其他事情} catch (InterruptedException e) {e.printStackTrace();}}
}
public class Demo12 {public static void main(String[] args) throws InterruptedException {// 核心线程数int corePoolSize = 2;// 最大线程数int maximumPoolSize = 4;// 线程空闲时间long keepAliveTime = 10;// 时间单位TimeUnit unit = TimeUnit.SECONDS;// 工作队列BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);// 线程工厂ThreadFactory threadFactory = Executors.defaultThreadFactory();// 拒绝策略RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();// 创建自定义线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);TaskRunnable taskRunnable = new TaskRunnable();for (int i = 0;i < 6; i++){executor.execute(taskRunnable);}}
}
  • 当提交的任务数 <= (最大线程数 + 任务队列大小),能正常工作
pool-1-thread-1 售出第5张票
pool-1-thread-4 售出第4张票
pool-1-thread-3 售出第3张票
pool-1-thread-2 售出第2张票
pool-1-thread-4 售出第1张票
pool-1-thread-1没票了
  • 当提交的任务数 > (最大线程数 + 任务队列大小),触发拒绝策略
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.binbin.usethread.TaskRunnable@34a245ab rejected from java.util.concurrent.ThreadPoolExecutor@7cc355be[Running, pool size = 4, active threads = 4, queued tasks = 2, completed tasks = 0]at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2065)at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:833)at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1365)at com.binbin.usethread.Demo12.main(Demo12.java:50)
pool-1-thread-1 售出第5张票
pool-1-thread-4 售出第4张票
pool-1-thread-3 售出第3张票
pool-1-thread-2 售出第2张票
pool-1-thread-4 售出第1张票
pool-1-thread-1没票了

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com