Java并发实战——线程池一篇详解

        本文将深入探讨Java线程池的各个方面,从基础概念到高级应用,从而全面掌握线程池的使用,解决频繁地创建和销毁线程带来巨大的系统开销,包括内存消耗、CPU 时间浪费等,通过复用线程,避免了线程的频繁创建和销毁,从而提高了系统的性能和稳定性。

本文目录

    • 一、线程池简介
    • 二、线程池优点
    • 三、线程池相关概念
      • ThreadPoolExecutor 的构造函数
      • 任务队列
      • 拒绝策略
    • 四、线程池的使用
    • 五、线程池工厂类
      • 固定大小线程池
      • 单线程线程池
      • 缓存线程池
      • 定时任务线程池

一、线程池简介

线程池就像是一个线程的管理工厂,预先创建一定数量的线程,并将这些线程存储在一个池中。当有任务提交时,线程池会从池中取出一个空闲线程来执行该任务。如果池中的线程都在忙碌,任务会被放入一个任务队列中等待执行。当线程完成任务后,它不会被销毁,而是返回线程池,等待下一个任务。



二、线程池优点

  1. 减少了线程的创建和销毁所带来的开销,提高了系统资源的利用率。
  2. 任务提交后,无需等待线程创建,可直接从线程池中获取线程执行任务。
  3. 可以对线程进行统一的管理和监控,如设置线程的最大数量、任务队列的大小等。



三、线程池相关概念

线程池的核心实现主要依赖于 java.util.concurrent 包中的 ExecutorService 接口及其实现类。其中,ThreadPoolExecutor 是最常用的线程池实现类。

ThreadPoolExecutor 的构造函数

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
  • corePoolSize:核心线程数,线程池会一直保持这些线程的存活,即使它们处于空闲状态。
  • maximumPoolSize:线程池允许的最大线程数。
  • keepAliveTime:当线程池中的线程数量超过核心线程数时,多余的空闲线程在被销毁之前等待新任务的最长时间。
  • unitkeepAliveTime 的时间单位。
  • workQueue:任务队列,用于存储等待执行的任务。
  • threadFactory:线程工厂,用于创建线程。
  • handler:拒绝策略,当任务队列已满且线程池中的线程数量达到最大线程数时,新提交的任务将由该策略处理。

任务队列

BlockingQueue 是用于实现任务队列的接口,常见的实现类有:

  • ArrayBlockingQueue:有界队列,使用数组实现,需要指定队列的容量。
  • LinkedBlockingQueue:可选有界或无界队列,使用链表实现。如果不指定容量,则默认为无界队列。
  • SynchronousQueue:没有容量的队列,每个插入操作必须等待另一个线程的移除操作,反之亦然。

拒绝策略

RejectedExecutionHandler 是用于处理拒绝任务的接口,常见的实现类有:

  • AbortPolicy:直接抛出 RejectedExecutionException 异常。
  • CallerRunsPolicy:由提交任务的线程来执行该任务。
  • DiscardPolicy:直接丢弃该任务,不做任何处理。
  • DiscardOldestPolicy:丢弃任务队列中最旧的任务,然后尝试提交新任务。



四、线程池的使用

import java.util.concurrent.*;

public class ThreadPoolUse {
    public static void main(String[] args) {
        // 创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                5, // 最大线程数
                60, // 空闲线程存活时间
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10), // 任务队列
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
        );

        // 提交任务
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("任务 " + taskId + " 正在运行 " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 运行完成");
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}

shutdown() 方法关闭线程池



五、线程池工厂类

为了方便使用,Java内置了Executors工具类,提供了一些静态方法来创建不同类型的线程池。

固定大小线程池

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

固定大小线程池的核心线程数和最大线程数相等,线程池中的线程数量始终保持不变。

单线程线程池

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

单线程线程池只有一个核心线程,所有任务会按照提交的顺序依次执行。

缓存线程池

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

缓存线程池的核心线程数为 0,最大线程数为 Integer.MAX_VALUE,它会根据任务的数量动态创建和销毁线程。

定时任务线程池

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

定时任务线程池可以用于执行定时任务和周期性任务。

实际开发中,建议尽量避免使用 Executors 工具类创建线程池,而是直接使用 ThreadPoolExecutor 来创建线程池,以便更好地控制线程池的参数。



← 上一篇 Java进阶——常用类及常用方法详解
记得点赞、关注、收藏哦!
下一篇 Java进阶——数组超详细整理 →

你可能感兴趣的:(Java并发,java,多线程)