Java线程池七个参数详解

2024-01-09 06:21:11

前言

直接点题

核心线程数 - corePoolSize

最大线程数 - maximumPoolSize

空闲线程存活时间 - keepAliveTime

存活时间单位 - unit

任务队列 - workQueue

线程工厂 - threadFactory

拒绝策略- handler

概念

什么是池?

池(Pool),可以把它理解为一个容器,里面装着各种我们所需要的资源,我们需要资源的时候去这个容器里面拿,而不需要每次使用的时候去创建,从而达到一个复用的效果提高资源可利用率。

线程池的概念

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。简单点理解就是在需要使用多线程执行任务的时候不需要进行线程的创建,而是把任务提交到线程池中由线程池按照一定的规则处理。

详解

1 corePoolSize(核心线程数)

corePoolSize表示核心线程数,核心线程数是指线程池中始终保持着活动的线程数量,可以这么理解,就算线程池中没有任务执行,线程为空闲状态也不会被回收。

但是也有可以被回收的情况,例如我们设置线程池中 allowCoreThreadTimeOut 为 true 那么核心线程数也会因为超过一定的阈值而被回收,设置 allowCoreThreadTimeOut 的案例如下
?

public class PoolTest {
 
    public static void main(String[] args) {
        // 创建一个阻塞队列,用于存放等待执行的任务
        BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10);
 
        // 创建自定义的线程池,设置核心线程数、最大线程数、等待时间、时间单位、任务队列等参数
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, queue);
 
        // 提交任务给线程池,使用 execute() 方法提交
        for (int i = 0; i < 10; i++) {
            Runnable task = new MyTask(i);
            executor.execute(task);
        }
 
        // 设置为 true 那么一些空闲的核心线程可能会在超过一分钟之后被回收掉
        executor.allowCoreThreadTimeOut(true);
 
        // 关闭线程池
        executor.shutdown();
    }
 
}
class MyTask implements Runnable {
    private final int taskId;
 
    public MyTask(int taskId) {
        this.taskId = taskId;
    }
 
    @SneakyThrows
    @Override
    public void run() {
        Thread.sleep(2000);
        System.out.println("Task ID : " + taskId + " 执行 " + Thread.currentThread().getName());
    }
}

2 maximumPoolSize(最大线程数)

线程池中允许的最大线程数量,包括核心线程和额外创建的临时线程数量。

在向线程池中提交任务的时,假如当前的任务数量超过了corePoolSize(核心线程数),同时workQueue(任务队列)也满了,那么就会根据需要来创建corePoolSize(核心线程数)之外的临时线程数,但 corePoolSize(核心线程数)和 临时线程数总数不能超过maximumPoolSize(最大线程数)。

3 keepAliveTime(空闲的线程存活时间)

它表示当线程处于空闲状态的时候或没有任务执行时,线程可额外存活的时间,如果这段额外的时间没有需要处理的任务,那么超过这个时间空闲的线程就会被终止并从线程池中移除。例如上面的例子,设置的是1分钟超时时间(可以自己设置),空闲时间超过一分钟线程就会被回收掉。
?

4 unit(时间单位)

是用于表示线程池中时间单位的枚举类型,提供了一个枚举类 java.util.concurrent.TimeUnit 可以配置枚举类中任意一种例如 TimeUnit.SECONDS 秒,TimeUnit.MINUTES 分钟,TimeUnit.HOURS 小时,TimeUnit.DAYS 天 等,配合 keepAliveTime(空闲的线程存活时间)进行使用。

5 workQueue(任务队列)

用于存储线程池中待执行任务的阻塞队列,通常下线程池中任务数量超过了 corePoolSize(核心线程数)时,那么新提交的任务就会被放至 workQueue(任务队列)当中,例如上面案例设置的任务队列大小为10,核心线程数为 5,当线程池正在执行的任务超过5的时候就会把新提交的任务暂放至任务队列当中,任务队列当中等待的任务最多为10个。

线程池的工作队列当中可以是不同的阻塞队列,案例中使用的是 LinkedBlockingQueue,常用的阻塞队列有:

  • ??? LinkedBlockingQueue:一个基于链表结构的可选有界阻塞队列,按照先进先出的顺序进行任务调度。如果不指定容量大小,则默认为 Integer.MAX_VALUE。
  • ??? PriorityBlockingQueue:一个基于优先级的无界阻塞队列,可以按照自定义的顺序执行任务。
  • ??? SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等待另一个线程的移除操作。在这种队列中,每个插入操作都会阻塞,直到有其他线程来获取数据。
  • ??? ArrayBlockingQueue:一个基于数组结构的有界阻塞队列,按照先进先出(FIFO)的顺序进行任务调度。
    ?

6 handler(拒绝策略)

用来处理线程池中的workQueue(任务队列)已满、并且线程池中的线程数已达到maximumPoolSize(最大线程数)时的情况,线程池会根据定义的拒绝策略来处理这些任务。

内置的拒绝策略有以下几种:

  • ??? AbortPolicy:直接抛出 RejectedExecutionException 异常,表示无法接受新任务,没有配置拒绝策略,默认为该策略。
  • ??? CallerRunsPolicy:将任务回退到调用者所在线程中执行,也就是由调用 execute 方法的线程来执行该任务。
  • ??? CallerRunsPolicy:将任务回退到调用者所在线程中执行,也就是由调用 execute 方法的线程来执行该任务。
  • ??? DiscardPolicy:直接丢弃无法处理的任务,不做任何处理。
  • ??? DiscardOldestPolicy:丢弃添加到工作队列最早的任务,并尝试重新提交当前任务。

7 threadFactory(创建线程工厂)

用来创建线程工厂的类,在线程池中需要创建新线程时使用 threadFactory(创建线程工厂) 进行创建线程对象,可以通过自定义 threadFactory(创建线程工厂)对线程进行个性化配置和定制,例如设置线程的名称、优先级等,可以更好的跟踪和管理线程池中的线程,例如以下案例给线程池中线程进行命名。
?

public class PoolTest {
 
    public static void main(String[] args) {
        int corePoolSize = 5;
        int maximumPoolSize = 10;
        long keepAliveTime = 1;
        TimeUnit unit = TimeUnit.MINUTES;
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
        ThreadFactory threadFactory = new MyThreadFactory(); // 自定义的ThreadFactory
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory
        );
 
        // csdn 骑电动车的小黄
        for (int i = 0; i < 10; i++) {
            // 提交任务到线程池
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    // 任务逻辑代码
                    System.out.println("开始执行任务 线程的自定义名称为:" + Thread.currentThread().getName());
                }
            });
        }
 
        // 关闭线程池...
        executor.shutdown();
    }
 
}
class MyThreadFactory implements ThreadFactory {
    private static final String THREAD_NAME_PREFIX = "这是一个线程自定义名称-";
    private int counter = 1;
 
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setName(THREAD_NAME_PREFIX + counter);
        thread.setPriority(Thread.NORM_PRIORITY);
        thread.setDaemon(false);
        counter++;
        return thread;
    }
}

文章来源:https://blog.csdn.net/qq_39535439/article/details/135468784
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。