我正在使用ExecutorService线程池执行可调用对象。我想给这个帖子命名。
更具体地说,在旧版本中我做到了这一点 -
Thread thread = new Thread(runnable Task);
thread.setName("My Thread Name");
我在log4j日志记录中使用线程名称,这在故障排除时有很大帮助。现在我将我的代码从Java 1.4迁移到Java 1.6。我写了这个(如下所示) - 但我不知道如何给这个帖子命名。
private final ExecutorService executorPool = Executors.newCachedThreadPool();
Future<String> result = executorPool.submit(callable Task);
请给我一些想法给这个帖子命名?
答案 0 :(得分:37)
我目前正在这样做:
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);
}
}
});
答案 1 :(得分:29)
您可以使用重载方法:
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,它可以利用内部匿名类的需要,甚至允许为你的线程自定义参数化名称。 / p>
答案 2 :(得分:10)
/**
* 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代表当前线程组中线程的顺序。
答案 3 :(得分:8)
当线程由线程池管理时重命名线程时应该小心,因为它们实际上是为了不同的任务而一遍又一遍地重复使用,一旦重命名,您可能会发现日志中的线程名称没有有意义......为了避免这种不必要的行为,你应该确保一旦你的Runnable / Callable完成,线程名称就会恢复。
实现这一点的一种方法是将一个由线程池执行的每个Runnable / Callable包装一个装饰器来处理所有需要的清理工作。
答案 4 :(得分:6)
如果您使用的是Spring,可以使用org.springframework.scheduling.concurrent.CustomizableThreadFactory:
ExecutorService executorService = Executors.newCachedThreadPool(
new CustomizableThreadFactory("MyThreadNamePrefix"));
答案 5 :(得分:2)
我只需要做你要求的事情 - 为我的线程组提供名字 - 所以感谢Andeas的回答,我创建了自己的ThreadFactory作为类的内部类,它将通过复制来使用它执行者$ DefaultThreadFactory,通过将参数“groupname”添加到构造函数来更改3行。
/**
* 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提出问题,感谢Andreas的回答。
答案 6 :(得分:0)
只需创建一个匿名的ThreadFactory来获取Executor服务。 ThreadFactory可以提供线程的名称,如下所示:&#34;线程A&#34;或者&#34;线程B&#34; (见例子)。
然后使用不同的执行程序服务调用可调用任务:
示例类:
public class 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;
}
}
答案 7 :(得分:0)
我使用过的一种方法,在我的例子中,我有一些期货并行获取由单个类控制的数据。我提交了一些工作并得到了期货。我将未来存储在地图中,其值为作业名称。 然后,当我在所有期货上超时时,我从地图上得到了这份工作的名字。这可能不是最灵活的方式,但在我的情况下工作。