如何为可调用线程命名?

时间:2010-07-12 08:59:02

标签: java multithreading executorservice java.util.concurrent

我正在使用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);

请给我一些想法给这个帖子命名?

8 个答案:

答案 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)

我使用过的一种方法,在我的例子中,我有一些期货并行获取由单个类控制的数据。我提交了一些工作并得到了期货。我将未来存储在地图中,其值为作业名称。 然后,当我在所有期货上超时时,我从地图上得到了这份工作的名字。这可能不是最灵活的方式,但在我的情况下工作。