Именование потоков и пулов потоков ExecutorService
Допустим у меня есть приложение, которое использует Executor база как таковая
Executors.newSingleThreadExecutor().submit(new Runnable(){
@Override
public void run(){
// do stuff
}
}
когда я запускаю это приложение в отладчике, создается поток со следующим именем (по умолчанию):Thread[pool-1-thread-1]. Как вы видите, это не очень полезно и, насколько я могу судить,Executor framework не предоставляет простой способ назвать созданные потоки или пулы потоков.
Итак, как можно предоставить имена для потоков/пулов потоков? Например, Thread[FooPool-FooThread].
14 ответов:
вы можете поставить
ThreadFactoryдоnewSingleThreadScheduledExecutor(ThreadFactory threadFactory). Фабрика будет отвечать за создание потоков и сможет их называть.цитировать документация:
создание новой темы
новые потоки создаются с помощью
ThreadFactory. Если не указано иное,Executors.defaultThreadFactory()используется, что создает потоки, чтобы все быть в том жеThreadGroupи с теми жеNORM_PRIORITYприоритет и не-демон статус. Путем предоставления различныхThreadFactory, вы можете изменить имя потока, группу потоков, приоритет, статус демона и т. д. Если aThreadFactoryне удается создать поток при запросе, возвращая null изnewThread, исполнитель продолжит, но не сможет выполнить никаких задач
гуава почти всегда имеет то, что вы нужно.
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("my-sad-thread-%d").build()и передайте его своему
ExecutorService.
вы можете попытаться предоставить свою собственную фабрику потоков, которая создаст поток с соответствующими именами. Вот один пример:
class YourThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) { return new Thread(r, "Your name"); } } Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);
вы также можете изменить имя вашего потока после этого, в то время как поток выполняется:
Thread.currentThread().setName("FooName");Это может быть интересно, если, например, вы используете один и тот же ThreadFactory для разных типов задач.
The
BasicThreadFactoryот apache commons-lang также полезно предоставить поведение именования. Вместо того, чтобы писать анонимный внутренний класс, вы можете использовать конструктор для именования потоков по своему усмотрению. Вот пример из 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);
здесь открыть RFE для этого с Oracle. Из комментариев сотрудника Oracle кажется, что они не понимают проблему и не будут исправлять. Это одна из тех вещей, которые мертво просто поддерживать в JDK (без нарушения обратной совместимости), так что это своего рода позор, что RFE получает неверное понимание.
как указано, вам нужно реализовать свой собственный ThreadFactory. Если вы не хотите тянуть в гуава или Apache Commons только для эту цель я предоставляю здесь
ThreadFactoryреализация, которую вы можете использовать. Это точно похоже на то, что вы получаете от JDK, за исключением возможности установить префикс имени потока на что-то другое, чем "пул".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. Вуаля!
Если вы используете Spring, есть
CustomizableThreadFactoryдля которого можно задать префикс имени потока.пример:
ExecutorService alphaExecutor = Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));
private class TaskThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, "TASK_EXECUTION_THREAD"); return t; } }передайте ThreadFactory в executorservice, и вы хорошо пойдете
расширения 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....и т. д.
Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob()); Runnable getJob() { return () -> { // your job }; }
вы можете написать свою собственную реализацию 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") );
Это моя подгонянная фабрика обеспечивая подгонянные имена для анализаторов сброса потока. Обычно я просто даю
tf=nullдля повторного использования фабрики резьбы по умолчанию JVM. этот вебсайт имеет более предварительную фабрику потока.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() ); } }
Я использую, чтобы сделать то же самое, как показано ниже :
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SO-POOL-%d").build(); ExecutorService executorService = Executors.newFixedThreadPool(5,namedThreadFactory);
Comments