Skip to main content
Select a menu in the customizer

Naming threads and thread pools of ExecutorService

如何替 ExecutorService 所管理的 thread 設定一個自己看得爽的名子

其實這是一件很重要的事情,根據 clean code 裡面所提到的,一個好的名子可以幫助你理解程式碼並 debug,通常配合 thread 觀測工具就可以找出到底有多少莫名其妙的 thread 在消耗你的資源。

以 android ddms 為例
ddms_thread

看得這邊你可能會覺得這篇很廢,不過是替 thread 取個名子,原生就有啦

Thread thread = new Thread(Runnable);
thread.setName("Load bitmap task");

但是~~~

如果是使用 ExecutorService 做為 thread 排程工具的話,就會發現居然沒有 setName() 可以用,這不是當然的嗎!就算可以取名子也會變成取 ExecutorService 的名子吧。而預設在 thread pool裡的 thread 一律是這格式(如上圖)

String namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-" + thredNumber.getAndIncrement();

基本上這命名有跟沒有差不多,只不過多知道這是由 pool 建出來的,為了解決這個問題,先提供最簡單的土砲法-直接在runnable 把 thread 抓出來命名

new Runnable () {
    public void run() {
        Thread.currentThread().setName("Your name");
        doStuff();
    }
}

但是這真的太土砲了,實在沒有美感,也代表者有跑到這個 runnable 的 thread 才有機會被命名,而且如果任務不同的話,一個thread 更有可能會常常變換名稱。

最好的方法是利用工廠模式,在創建 thread pool 時把創造 thread 的工廠方法也放進去

ExecutorService mPool;
public ExecutorService getExecutorPool() {
        if (mPool == null) {
            mPool = Executors.newFixedThreadPool(POOL_THREAD_NUM, new NameThreadFactory(TAG));
        }
        return mPool;
    }
}
// 另外寫的 thread factory, 簡單只多加命名的工作
public class NameThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    public NameThreadFactory(String namePrefix) {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                Thread.currentThread().getThreadGroup();
        this.namePrefix = namePrefix + "-" +
                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;
    }
}

或者更簡單的使用已有的車輪 guava , google common lib
先必須在 gradle 加上

compile 'com.google.guava:guava:18.0'

接者~

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                                       .setNameFormat("workerthread-%d").build()

也或者 apache 的這一套 lib ,請先抓jar下來

BasicThreadFactory factory = new BasicThreadFactory.Builder()
     .namingPattern("workerthread-%d")
     .daemon(true)
     .build();

感謝收看

reference:
http://stackoverflow.com/questions/6113746/naming-threads-and-thread-pools-of-executorservice