关键词

Java线程池中多余的线程是如何回收的

Java线程池可以有效控制线程的数量,提高程序的性能和资源利用率。但是在使用线程池的过程中,我们需要考虑线程池中多余的线程是如何回收的。下面我将从线程池的工作原理、线程池中的线程回收机制两个方面讲解这个问题。

线程池的工作原理

线程池在创建时会预先分配一定数量的线程。当用户提交任务时,线程池就会将任务分配给其中的一个空闲线程执行。如果线程池中没有空闲的线程,那么任务就会进入任务队列等待执行。当一个线程完成了任务后,它会从任务队列中取出下一个任务执行。

线程池中的线程回收机制

线程池中的线程回收机制主要体现在两个方面:空闲线程的回收和超时线程的回收。

1. 空闲线程的回收

线程池中的线程通常分为核心线程和非核心线程。当线程池中的线程数大于核心线程数时,非核心线程就成为了多余的线程。这些多余的线程默认情况下会在经过一定时间后被回收。具体实现方式取决于线程池的实现,可以有如下两种方式:

  1. Java自带的线程池实现类ThreadPoolExecutor采用了一种maxIdleTime为60秒的回收策略。当有线程处于空闲状态超过60秒时,就会被回收。

  2. HikariCP线程池的实现类HikariThreadPoolExecutor采用了一种新的回收策略,称之为熔断策略。当空闲线程存活时间超过maxLifetime时,会进入熔断状态。在熔断状态下,线程的空闲时间不会被计算。只有当线程池中的线程小于核心线程数时,才会回收处于熔断状态的线程。

2. 超时线程的回收

超时线程是指线程执行任务时超过给定时间限制的线程。具体实现方式也有如下的两种:

  1. 在ThreadPoolExecutor中,可以通过设置allowCoreThreadTimeOut参数为true来启动超时线程的回收机制。当一个线程处于空闲状态超过keepAliveTime时间,并且线程池中的线程数量大于corePoolSize,那么这个线程就会被回收。

  2. 在HikariCP线程池中,超时线程的回收机制是通过设置threadTimeout = 30秒实现的。当一个线程执行任务的时间超过30秒时,会被认为超时,线程就会被回收。

示例说明

下面通过两个简单的示例来说明Java线程池中多余的线程是如何回收的。

public class ThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            executorService.execute(() -> {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "执行任务完毕");
            });
        }
        executorService.shutdown();
    }
}

上面的示例中,创建了一个具有5个线程的线程池,然后提交了10个任务给线程池执行。由于线程池中的核心线程数为5,非核心线程数为5,因此只有5个线程可以同时执行任务,剩下的5个任务会进入任务队列等待执行。当一个线程完成任务后,它会继续等待下一个任务执行。如果线程空闲时间超过60秒,那么就会被回收。

public class ThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(5, 10,
                60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(20),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        for (int i = 0; i < 30; i++) {
            executorService.execute(() -> {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "执行任务完毕");
            });
        }
        executorService.shutdown();
    }
}

上面的示例中,创建了一个具有5个核心线程和10个最大线程的线程池,超时时间为60秒。提交了30个任务给线程池执行。由于任务执行时间为10秒,因此线程池中只有5个线程可以同时执行任务,剩下的25个任务会进入任务队列等待执行。当线程空闲时间超过60秒时,多余的线程就会被回收。如果在任务执行时超过60秒,那么线程也会被回收。

本文链接:http://task.lmcjl.com/news/8089.html

展开阅读全文