以ThreadPoolExecutor为例

ThreadPoolExecutor 有参构造方法提供了七个参数,根据这7个对应参数可以按照业务需求自定义合适的线程池,ThreadPoolExecutor 自定义线程池Demo 可以参考 ==> JAVA线程池创建的几种方式,有案例很细!!!(持续更新中)_骑电动车的小黄的博客-CSDN博客,具体的参数含义与作用请往下看。

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、keepAliveTime(空闲的线程存活时间)

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

3、unit(时间单位)

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

4、workQueue(任务队列)

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

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

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

5、maximumPoolSize(最大线程数)

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

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

6、handler(拒绝策略)

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

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

  1. AbortPolicy:直接抛出 RejectedExecutionException 异常,表示无法接受新任务,没有配置拒绝策略,默认为该策略。
  2. CallerRunsPolicy:将任务回退到调用者所在线程中执行,也就是由调用 execute 方法的线程来执行该任务。
  3. CallerRunsPolicy:将任务回退到调用者所在线程中执行,也就是由调用 execute 方法的线程来执行该任务。
  4. DiscardPolicy:直接丢弃无法处理的任务,不做任何处理。
  5. 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;
    }
}

执行结果:

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐