2011-12-15 58 views
9

我在Java中使用ThreadPoolExecutor来管理很多正在运行的线程。我已经创建了自己的简单ThreadFactory,所以我可以给线程更好的名字。使用ThreadPoolExecutor,如何获取在线程池中运行的线程的名称?

问题是当线程池第一次创建时,名称在线程中被设置,并且不与线程池实际运行的任务绑定。我明白这一点......我的Runnables和Callables - 尽管他们有名字 - 实际上是从ThreadPoolExecutor的运行线程中抽象出来的一个级别。

关于为ThreadPoolExecutor线程池创建名称,StackOverflow还存在其他一些问题。 (请参阅How to give name to a callable Thread?How to name the threads of a thread pool in Java。)

我想知道的是:有没有人有一个很好的解决方案来保持线程池线程的名称与它实际运行的Runnable同步?

即如果我打电话Thread.getCurrentThread().getName()我想它返回顶级的线程池的名称,而是线程当前运行的可赎回/ Runnable接口的名称。

因为这主要是为了调试和日志记录的目的,我试图避免一个解决方案,涉及到将每个Runnable提交给ThreadPoolExecutor的新代码 - 我只是将一些代码放入ThreadFactory或包装ThreadPoolExecutor本身,以便在一个位置完成更改。如果这样的解决方案不存在,我可能不会打扰,因为它不是任务关键。

开始编辑为了澄清,我知道我可以把一个Thread.currentThread().setName("my runnable name");,因为每个Runnable的run方法的第一线,但我想避免这样做。我在这里是一个完美主义者,我意识到这一点,所以如果人们想对这个问题发表评论并告诉我,我不会感到生气。 年底编辑

我的其他问题,我想,是人们是否认为这是一个坏主意,做这样的事情。我应该谨慎更新线程池名称吗?

感谢您的任何建议!

+0

“同步与Runnable接口保持线程池线程的名称,它实际上是运行” - > Runnable接口/赎回没有定义一个名字,所以我不能完全看到你的问题的重点。你的ThreadFactory是否给每个线程一个不同的名字? – serg10 2011-12-15 16:41:17

+0

对,我的每个Runnables和Callables都实现了一个Named接口,所以我可以访问名称。我意识到我很挑剔,因为我已经为所有Runnables实现了一个特殊功能,但是希望避免添加手动设置线程名称的其他代码。 – 2011-12-15 16:51:19

+1

为了清晰起见编辑,将一些“线程池”更改为“线程”,将一些“线程”更改为“任务”。 – 2011-12-15 17:01:14

回答

13

创建一个覆盖beforeExecute方法的ThreadPoolExecutor。

private final ThreadPoolExecutor executor = new ThreadPoolExecutor (new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()){ 
    protected void beforeExecute(Thread t, Runnable r) { 
     t.setName(deriveRunnableName(r)); 
    } 

    protected void afterExecute(Runnable r, Throwable t) { 
     Thread.currentThread().setName(""); 
    } 

    protected <V> RunnableFuture<V> newTaskFor(final Runnable runnable, V v) { 
     return new FutureTask<V>(runnable, v) { 
      public String toString() { 
       return runnable.toString(); 
      } 
     }; 
    }; 
} 

不知道究竟如何derveRunnableName()会的工作,也许toString()

编辑:Thread.currentThread()实际上是在beforeExecute中设置的线程,它调用afterExecute。您可以引用Thread.currentThread(),然后在afterExecute中设置名称。这是在的javadoc

/** 
* Method invoked upon completion of execution of the given Runnable. 
* This method is invoked by the thread that executed the task. If 
* non-null, the Throwable is the uncaught <tt>RuntimeException</tt> 
* or <tt>Error</tt> that caused execution to terminate abruptly. 
* 
* <p><b>Note:</b> When actions are enclosed in tasks (such as 
* {@link FutureTask}) either explicitly or via methods such as 
* <tt>submit</tt>, these task objects catch and maintain 
* computational exceptions, and so they do not cause abrupt 
* termination, and the internal exceptions are <em>not</em> 
* passed to this method. 
* 
* <p>This implementation does nothing, but may be customized in 
* subclasses. Note: To properly nest multiple overridings, subclasses 
* should generally invoke <tt>super.afterExecute</tt> at the 
* beginning of this method. 
* 
* @param r the runnable that has completed. 
* @param t the exception that caused termination, or null if 
* execution completed normally. 
*/ 
protected void afterExecute(Runnable r, Throwable t) { } 

编辑指出的TPE将包装了Runnable一个FutureTask内,所以要支持toString方法,你可以覆盖newTaskFor并创建自己的包裹FutureTask。

2

我的建议是尝试

pool.execute(new Runnable() { 
    public void run() { 
     Thread.getCurrentThread().setName("My descriptive Runnable"); 
     // do my descriptive Runnable 
    } 
});     

您也可以重置这个名字的时候,你如果你喜欢已经完成。

+0

你是否建议我每次打电话给pool.execute时都这样做,或者我重写池的执行方法? – 2011-12-15 16:59:33

4

所以,我有一个解决方案,管理名称后设置名称和清理。感谢Peter Lawrey和John Vint对我的建议。由于没有建议完全处理我的问题,我想我会发布此示例代码作为一个单独的答案。我很抱歉,如果这是糟糕的礼节 - 如果是这样,让我知道,我会调整。

在下面的代码中,我决定保留原始ThreadPoolExecutor线程的名称并追加Runnable名称,然后在finally块中删除Runnable名称进行清理,但可以轻松更改该名称。

正如约翰Vint的建议,我宁愿重写beforeExecution方法,然后重写afterExecution方法来清理,但afterExecution没有一个句柄线程。

public class RunnableNameThreadPoolExecutor extends ThreadPoolExecutor { 

    /* Constructors... */ 

    @Override 
    public void execute(Runnable command) { 
     super.execute(new ManageNameRunnable(command)); 
    } 

    private class ManageNameRunnable implements Runnable { 
     private final Runnable command; 
     ManageNameRunnable(Runnable command) { 
      this.command = command; 
     } 

     public void run() { 
      String originalName = Thread.currentThread().getName(); 
      try { 
       String runnableName = getRunnableName(command); 
       Thread.currentThread().setName(originalName+ ": " + runnableName); 
       command.run(); 
      } finally { 
       Thread.currentThread().setName(originalName); 
      } 
     } 
    } 
} 
相关问题