在项目中使用JAVA线程池,日志打印的线程名为
pool-1-thread-1
格式,我们无法准确定位到是什么业务在使用线程。而线程池中线程的创建,由ThreadFactory
接口来实现。那么我们自定义线程工厂类便可以解决该问题。1. 测试代码
@Slf4j public class ThreadTest { public static void main(String[] args) { * 使用Spring提供的ThreadFactory ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 100 , TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new CustomizableThreadFactory("demo-")); executor.execute(() -> { log.info("CustomizableThreadFactory数据..."); ThreadPoolExecutor executor2 = new ThreadPoolExecutor(1, 1, 100 , TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); executor2.execute(() -> { log.info("executor2数据..."); ThreadPoolExecutor executor3 = new ThreadPoolExecutor(1, 1, 100 , TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); executor3.execute(() -> { log.info("executor3数据...");
11:31:32.010 [pool-1-thread-1] INFO com.tellme.demo.ThreadTest - executor2数据... 11:31:32.010 [demo-1] INFO com.tellme.demo.ThreadTest - CustomizableThreadFactory数据... 11:38:17.462 [pool-2-thread-1] INFO com.tellme.demo.ThreadTest - executor3数据...
可以看到,当使用JAVA默认的线程池工厂类创建线程池时,
pool-2...
是递增的。2. 默认的ThreadFactory
* 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(), if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t;注意:
poolNumber
是static变量,即全局递增。threadNumber
为常量,每个对象递增。我们重实现ThreadFactory,可以将线程池前缀传入。
3. 自定义的ThreadFactory
源码位置:
com.alibaba.dubbo.common.utils.NamedThreadFactory
public class NamedThreadFactory implements ThreadFactory { protected static final AtomicInteger POOL_SEQ = new AtomicInteger(1); protected final AtomicInteger mThreadNum = new AtomicInteger(1); protected final String mPrefix; protected final boolean mDaemon; protected final ThreadGroup mGroup; public NamedThreadFactory() { this("pool-" + POOL_SEQ.getAndIncrement(), false); public NamedThreadFactory(String prefix) { this(prefix, false); public NamedThreadFactory(String prefix, boolean daemon) { mPrefix = prefix + "-thread-"; mDaemon = daemon; SecurityManager s = System.getSecurityManager(); mGroup = (s == null) ? Thread.currentThread().getThreadGroup() : s.getThreadGroup(); @Override public Thread newThread(Runnable runnable) { String name = mPrefix + mThreadNum.getAndIncrement(); Thread ret = new Thread(mGroup, runnable, name, 0); ret.setDaemon(mDaemon); return ret; public ThreadGroup getThreadGroup() { return mGroup;
便可以传入线程池名称和决定是否为守护线程。
4. ThreadFactory深入理解
线程池是重复理利用线程资源,所以ThreadFactory的 newThread
方法是第一次创建线程时才会被调用;调用 java.util.concurrent.ThreadFactory#newThread
时创建子线程,是主线程执行的。