并发编程系列之自定义可以命名的线程池工厂类

本文通过一个Java多线程的例子展示了如何创建线程池,并解释了默认线程命名规则。通过查看`ThreadPoolExecutor`和`DefaultThreadFactory`源码,了解到线程名的生成方式。为了解决线程定位问题,自定义了`NamedThreadFactory`,使得线程名更具业务意义,便于调试和跟踪。实验结果显示,自定义线程工厂成功实现了线程命名的定制化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用多线程时候,有时候需要记录具体是哪些业务执行的,不过按照默认的情况,是会打印pool-1-thread-1这种类型的数据,所以有时候不能确定具体哪些业务线程执行的,可以先写一个线程池sample类,运行看看情况:


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExample {

    public static void main(String[] args) {
        ExecutorService orderThreadPool = new ThreadPoolExecutor(2, 5,
                60L, TimeUnit.SECONDS,
                new ArrayBlockingQueue(5));
        ExecutorService sendThreadPool = new ThreadPoolExecutor(2, 5,
                60L, TimeUnit.SECONDS,
                new ArrayBlockingQueue(5));
        orderThreadPool.execute(new OrderTask());
        sendThreadPool.execute(new SendTask());
        // 避免内存泄露,记得关闭线程池
        orderThreadPool.shutdown();
        sendThreadPool.shutdown();
    }

    static class OrderTask implements Runnable {
        @Override
        public void run() {
            System.out.println(String.format("thread name:%s",Thread.currentThread().getName()));
            System.out.println("保存订单信息");
        }
    }

    static class SendTask implements Runnable {
        @Override
        public void run() {
            System.out.println(String.format("thread name:%s",Thread.currentThread().getName()));
            System.out.println("保存发货信息");
        }
    }

}

控制台打印,不能定位是哪些线程

thread name:pool-1-thread-1
保存订单信息
thread name:pool-2-thread-1
保存发货信息

跟一下源码:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

默认使用了线程池工厂类

public static ThreadFactory defaultThreadFactory() {
   return new DefaultThreadFactory();
}

默认的线程池工厂,namePrefix = "pool-" +poolNumber.getAndIncrement() + "-thread-";,使用一个原子类,命名规则是这样的

/**
 * The default thread factory
 */
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

所以,这边简单改下代码,传一个自定义的name进去就行


import org.springframework.util.StringUtils;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class NamedThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    /** 线程组 **/
    private final ThreadGroup group;
    /** 原子类保证计数线程安全 **/
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    /** 命名前缀 **/
    private final String namePrefix;

    NamedThreadFactory(String threadFactoryName) {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                Thread.currentThread().getThreadGroup();
        threadFactoryName = StringUtils.isEmpty(threadFactoryName)
                ? "pool-"
                : threadFactoryName + "-";
        namePrefix = threadFactoryName + poolNumber.getAndIncrement()+ "-thread-";
    }
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                namePrefix + threadNumber.getAndIncrement(),
                0);
        // 守护线程
        if (t.isDaemon())
            t.setDaemon(false);
        // 优先级
        if (t.getPriority() != Thread.NORM_PRIORITY)
            // 标准优先级
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

将自定义的NamedThreadFactory类传进去

ExecutorService orderThreadPool = new ThreadPoolExecutor(2, 5,
                60L, TimeUnit.SECONDS,
                new ArrayBlockingQueue(5),
                new NamedThreadFactory("orderPool"));

控制台打印

thread name:sendPool-2-thread-1
保存发货信息
thread name:orderPool-1-thread-1
保存订单信息

OK,例子是比较简单的,不过目的是通过例子,看看源码的实现原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nicky.Ma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值