Как указать имя вызываемой теме?
Я выполняю вызываемый объект, используя пул потоков ExecutorService. Я хочу дать название этой теме.
Чтобы быть более конкретным, в более старой версии я сделал это -
Thread thread = new Thread(runnable Task);
thread.setName("My Thread Name");
Я использую имя потока в log4j logging, это помогает во время устранения неполадок. Теперь я переношу свой код с Java 1.4 на Java 1.6. Я написал это (учитывая ниже) - но я не знаю, как назвать имя этой теме.
private final ExecutorService executorPool = Executors.newCachedThreadPool();
Future<String> result = executorPool.submit(callable Task);
Пожалуйста, дайте мне идею дать название этой теме?
Ответы
Ответ 1
Вы можете использовать перегруженный метод:
java.util.concurrent.Executors.newCachedThreadPool(ThreadFactory)
который позволяет вам передать
java.util.concurrent.ThreadFactory
который должен позволять вам устанавливать имена потоков через java.util.concurrent.ThreadFactory.newThread(Runnable)
:
Создает новый Thread
. Реализации также могут инициализировать приоритет, имя, статус демона, ThreadGroup
и т.д.
Взгляните на java.util.concurrent.Executors.DefaultThreadFactory
для реализации по умолчанию.
Добавление
Так как я вижу, что этот поток по-прежнему посещен, Guava (если у вас есть) доступен ThreadFactoryBuilder, который использует необходимость наличия внутреннего анонимного класса и даже позволяет настраивать параметризованные имена для ваших потоков.
Ответ 2
В настоящее время я делаю это примерно так:
someExecutor.execute(new Runnable() {
@Override public void run() {
final String orgName = Thread.currentThread().getName();
Thread.currentThread().setName(orgName + " - My custom name here");
try {
myAction();
} finally {
Thread.currentThread().setName(orgName);
}
}
});
Ответ 3
/**
* The default thread factory
*/
static class DefaultThreadFactory implements ThreadFactory {
static final AtomicInteger poolNumber = new AtomicInteger(1);
final ThreadGroup group;
final AtomicInteger threadNumber = new AtomicInteger(1);
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;
}
}
Это оригинальная реализация в Java 1.5.0. Итак, у вас есть имена как pool-x-thread, где x обозначает порядок потока в текущей группе потоков.
Ответ 4
Вы должны быть осторожны при переименовании потоков, когда ваши потоки управляются пулом потоков, поскольку они на самом деле повторно используются для разных задач и после переименования вы можете обнаружить, что имена потоков в ваших журналах не являются иметь какой-то смысл... Чтобы избежать этого нежелательного поведения, вы должны убедиться, что после того, как ваш Runnable/Callable завершит восстановление имени потока,
Один из способов реализации этого - обматывать каждый Runnable/Callable, который выполняется пулом потоков с помощью декоратора, который обрабатывает все необходимые очистки.
Ответ 5
Если вы используете Spring, вы можете использовать org.springframework.scheduling.concurrent.CustomizableThreadFactory для этого:
ExecutorService executorService = Executors.newCachedThreadPool(
new CustomizableThreadFactory("MyThreadNamePrefix"));
Ответ 6
Мне просто нужно было делать то, о чем вы просите, - предоставляя имена моим группам нитей - поэтому, благодаря ответу Andeas, я создал свой собственный ThreadFactory в качестве внутреннего класса для класса, который будет использовать его, копируя Исполнители $DefaultThreadFactory, изменяя 3 строки, добавляя в конструктор параметр "groupname".
/**
* A thread factory that names each thread with the provided group name.
* <p>
* Except lines with "elarson modified", copied from code
* Executors$DefaultThreadFactory -- Doug Lea, Copyright Oracle, et al.
*/
static class GroupNameThreadFactory implements ThreadFactory {
private String groupname; /* elarson modified */
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
GroupNameThreadFactory(String groupname) {
this.groupname = groupname; /* elarson modified */
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
this.groupname + /* elarson modified */
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;
}
}
Создание ThreadPool из него выполняется следующим образом.
ThreadFactory threadfactory = new GroupNameThreadFactory("Monitor");
executor = Executors.newFixedThreadPool(NUM_THREADS, threadfactory);
Спасибо пользователю381878 за вопрос, и Андреас за ответ.
Ответ 7
Просто создайте анонимный ThreadFactory для получения службы-исполнителя.
ThreadFactory может предоставить имя для потока следующим образом: "Thread A" или "Thread B" (см. Пример).
Затем вызовите вызываемую задачу, используя различные службы-исполнители:
Пример Класс:
открытый класс ThreadTester {
public static void main(String[] args) {
ThreadTester threadTester = new ThreadTester();
threadTester.test();
}
private void test() {
ExecutorService executorservice = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable arg0) {
return new Thread(arg0,"Thread A");
}
});
CallableTask taskA = new CallableTask();
executorservice.submit(taskA);
executorservice = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable arg0) {
return new Thread(arg0,"Thread B");
}
});
CallableTask taskB = new CallableTask();
executorservice.submit(taskB);
}
}
Запрашиваемая задача:
Открытый класс CallableTask реализует Callable {
@Override
public Integer call() throws Exception {
int sum = 0;
for(int count=1;count<=30;count++){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " Count :"+count);
sum = sum + count;
}
System.out.println(Thread.currentThread().getName() + " Sum :"+sum);
return sum;
}
}
Ответ 8
Один подход, который я использовал, и в моем случае у меня было несколько фьючерсов, которые собирали данные параллельно, контролируемые одним классом. Я подаю несколько заданий и верну их фьючерсы. Я сохраняю будущее на карте со значением в качестве имени задания.
Затем, позже, когда я получаю таймаут во всех фьючерсах, у меня есть имя задания с карты. Это не самый гибкий способ, но он работал в моей ситуации.