首页 文章

命名ExecutorService的线程和线程池

提问于
浏览
179

假设我有一个使用 Executor 框架的应用程序

Executors.newSingleThreadExecutor().submit(new Runnable(){
    @Override
    public void run(){
        // do stuff
    }
}

当我在调试器中运行此应用程序时,将使用以下(默认)名称创建一个线程: Thread[pool-1-thread-1] . 正如您所看到的,这并不是非常有用,据我所知, Executor 框架并没有提供一种简单的方法来命名创建的线程或线程池 .

那么,如何为线程/线程池提供名称呢?例如, Thread[FooPool-FooThread] .

14 回答

  • 41

    Guava 几乎总是有你的need .

    ThreadFactory namedThreadFactory = 
      new ThreadFactoryBuilder().setNameFormat("my-sad-thread-%d").build()
    

    把它传递给你 ExecutorService .

  • 17

    您可以尝试提供自己的线程工厂,它将创建具有适当名称的线程 . 这是一个例子:

    class YourThreadFactory implements ThreadFactory {
       public Thread newThread(Runnable r) {
         return new Thread(r, "Your name");
       }
     }
    
    Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);
    
  • 8

    您还可以在执行线程时更改线程的名称:

    Thread.currentThread().setName("FooName");
    

    例如,如果您将不同类型的任务用于相同的ThreadFactory,那么这可能是有意义的 .

  • 6

    你可以提供ThreadFactorynewSingleThreadScheduledExecutor(ThreadFactory threadFactory) . 工厂将负责创建线程,并且能够命名它们 .

    引用Javadoc

    创建新线程使用ThreadFactory创建新线程 . 如果没有另外指定,则使用Executors.defaultThreadFactory(),它将所有线程创建在同一个ThreadGroup中,并具有相同的NORM_PRIORITY优先级和非守护进程状态 . 通过提供不同的ThreadFactory,您可以更改线程的名称,线程组,优先级,守护程序状态等 . 如果ThreadFactory在通过从newThread返回null请求时无法创建线程,则执行程序将继续,但可能无法执行任何任务

  • 0

    来自apache commons-lang的BasicThreadFactory对于提供命名行为也很有用 . 您可以使用Builder根据需要命名线程,而不是编写匿名内部类 . 这是来自javadocs的示例:

    // Create a factory that produces daemon threads with a naming pattern and
     // a priority
     BasicThreadFactory factory = new BasicThreadFactory.Builder()
         .namingPattern("workerthread-%d")
         .daemon(true)
         .priority(Thread.MAX_PRIORITY)
         .build();
     // Create an executor service for single-threaded execution
     ExecutorService exec = Executors.newSingleThreadExecutor(factory);
    
  • 3

    对于Oracle来说,这是一个open RFE . 根据Oracle员工的评论,似乎他们没有解决问题 . 这是JDK中支持简单易用的东西之一(没有破坏向后兼容性),因此RFE被误解是一种耻辱 .

    正如所指出的,你需要实现自己的ThreadFactory . 如果你不想仅仅为了这个目的而引入Guava或Apache Commons,我在这里提供了一个你可以使用的 ThreadFactory 实现 . 它与您从JDK获得的内容完全相似,除了能够将线程名称前缀设置为"pool"之外的其他内容 .

    package org.demo.concurrency;
    
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * ThreadFactory with the ability to set the thread name prefix. 
     * This class is exactly similar to 
     * {@link java.util.concurrent.Executors#defaultThreadFactory()}
     * from JDK8, except for the thread naming feature.
     *
     * <p>
     * The factory creates threads that have names on the form
     * <i>prefix-N-thread-M</i>, where <i>prefix</i>
     * is a string provided in the constructor, <i>N</i> is the sequence number of
     * this factory, and <i>M</i> is the sequence number of the thread created 
     * by this factory.
     */
    public class ThreadFactoryWithNamePrefix implements ThreadFactory {
    
        // Note:  The source code for this class was based entirely on 
        // Executors.DefaultThreadFactory class from the JDK8 source.
        // The only change made is the ability to configure the thread
        // name prefix.
    
    
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
    
        /**
         * Creates a new ThreadFactory where threads are created with a name prefix
         * of <code>prefix</code>.
         *
         * @param prefix Thread name prefix. Never use a value of "pool" as in that
         *      case you might as well have used
         *      {@link java.util.concurrent.Executors#defaultThreadFactory()}.
         */
        public ThreadFactoryWithNamePrefix(String prefix) {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup()
                    : Thread.currentThread().getThreadGroup();
            namePrefix = prefix + "-"
                    + 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;
        }
    }
    

    当您想要使用它时,您只需利用所有 Executors 方法允许您提供自己的 ThreadFactory 这一事实 .

    这个

    Executors.newSingleThreadExecutor();
    

    将给出一个ExecutorService,其中线程名为 pool-N-thread-M 但是使用了

    Executors.newSingleThreadExecutor(new ThreadFactoryWithNamePrefix("primecalc");
    

    你会得到一个ExecutorService,其中的线程名为 primecalc-N-thread-M . 瞧!

  • 45

    如果您使用的是Spring,则可以使用CustomizableThreadFactory设置线程名称前缀 .

    例:

    ExecutorService alphaExecutor =
        Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));
    
  • 14
    private class TaskThreadFactory implements ThreadFactory
    {
    
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "TASK_EXECUTION_THREAD");
    
            return t;
        }
    
    }
    

    将ThreadFactory传递给 Actuator 服务器,你很高兴

  • 237

    一种快速而肮脏的方法是在 run() 方法中使用 Thread.currentThread().setName(myName); .

  • 95

    延长ThreadFactory

    public interface ThreadFactory

    按需创建新线程的对象 . 使用线程工厂删除了对新线程的调用的硬连接,使应用程序能够使用特殊的线程子类,优先级等 .

    Thread newThread(Runnable r)

    构造一个新线程 . 实现还可以初始化优先级,名称,守护程序状态,ThreadGroup等 .

    示例代码:

    import java.util.concurrent.*;
    import java.util.concurrent.atomic.*;
    
    import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy;
    
    class SimpleThreadFactory implements ThreadFactory {
       String name;
       AtomicInteger threadNo = new AtomicInteger(0);
    
       public SimpleThreadFactory (String name){
           this.name = name;
       }
       public Thread newThread(Runnable r) {
         String threadName = name+":"+threadNo.incrementAndGet();
         System.out.println("threadName:"+threadName);
         return new Thread(r,threadName );
       }
       public static void main(String args[]){
            SimpleThreadFactory factory = new SimpleThreadFactory("Factory Thread");
            ThreadPoolExecutor executor= new ThreadPoolExecutor(1,1,60,
                        TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(1),new ThreadPoolExecutor.DiscardPolicy());
    
    
            final ExecutorService executorService = Executors.newFixedThreadPool(5,factory);
    
            for ( int i=0; i < 100; i++){
                executorService.submit(new Runnable(){
                     public void run(){
                        System.out.println("Thread Name in Runnable:"+Thread.currentThread().getName());
                     }
                });
            }
            executorService.shutdown();
        }
     }
    

    输出:

    java SimpleThreadFactory
    
    thread no:1
    thread no:2
    Thread Name in Runnable:Factory Thread:1
    Thread Name in Runnable:Factory Thread:2
    thread no:3
    thread no:4
    Thread Name in Runnable:Factory Thread:3
    Thread Name in Runnable:Factory Thread:4
    thread no:5
    Thread Name in Runnable:Factory Thread:5
    

    ....等等

  • 5
    Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob());
    
    Runnable getJob() {
            return () -> {
                // your job
            };
    }
    
  • 75

    您可以编写自己的ThreadFactory实现,例如使用一些现有的实现(如defaultThreadFactory)并在最后更改名称 .

    实现ThreadFactory的示例:

    class ThreadFactoryWithCustomName implements ThreadFactory {
        private final ThreadFactory threadFactory;
        private final String name;
    
        public ThreadFactoryWithCustomName(final ThreadFactory threadFactory, final String name) {
            this.threadFactory = threadFactory;
            this.name = name;
        }
    
        @Override
        public Thread newThread(final Runnable r) {
            final Thread thread = threadFactory.newThread(r);
            thread.setName(name);
            return thread;
        }
    }
    

    用法:

    Executors.newSingleThreadExecutor(new ThreadFactoryWithCustomName(
            Executors.defaultThreadFactory(),
            "customName")
        );
    
  • 3

    这是我的定制工厂,为线程转储分析器提供自定义名称 . 通常我只是给 tf=null 重用JVM默认的线程工厂 . This website has more advanced thread factory.

    public class SimpleThreadFactory implements ThreadFactory {
        private ThreadFactory tf;
        private String nameSuffix;
    
        public SimpleThreadFactory (ThreadFactory tf, String nameSuffix) {
            this.tf = tf!=null ? tf : Executors.defaultThreadFactory();
            this.nameSuffix = nameSuffix; 
        }
    
        @Override public Thread newThread(Runnable task) {
            // default "pool-1-thread-1" to "pool-1-thread-1-myapp-MagicTask"
            Thread thread=tf.newThread(task);
            thread.setName(thread.getName()+"-"+nameSuffix);
            return thread;
        }
    }
    
    - - - - - 
    
    ExecutorService es = Executors.newFixedThreadPool(4, new SimpleThreadFactory(null, "myapp-MagicTask") );
    

    为方便起见,这是一个用于调试目的的线程转储循环 .

    ThreadMXBean mxBean=ManagementFactory.getThreadMXBean();
        long[] tids = mxBean.getAllThreadIds();
        System.out.println("------------");
        System.out.println("ThreadCount="+tids.length);
        for(long tid : tids) {
            ThreadInfo mxInfo=mxBean.getThreadInfo(tid);
            if (mxInfo==null) {
                System.out.printf("%d %s\n", tid, "Thread not found");
            } else {
                System.out.printf("%d %s, state=%s, suspended=%d, lockowner=%d %s\n"
                        , mxInfo.getThreadId(), mxInfo.getThreadName()
                        , mxInfo.getThreadState().toString()
                        , mxInfo.isSuspended()?1:0
                        , mxInfo.getLockOwnerId(), mxInfo.getLockOwnerName()
                );
            }
        }
    
  • 3

    我用来做同样的事情(需要 guava 库):

    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SO-POOL-%d").build();
    ExecutorService executorService = Executors.newFixedThreadPool(5,namedThreadFactory);
    

相关问题