web-dev-qa-db-ja.com

呼び出し可能なスレッドに名前を付ける方法は?

ExecutorServiceスレッドプールを使用してCallable Objectを実行しています。このスレッドに名前を付けたいです。

具体的には、古いバージョンでこれを行いました-

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);

このスレッドに名前を付けるアイデアを教えてください。

34
user381878

オーバーロードされたメソッドを使用できます:

_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 を提供します。これは、内部の匿名クラスの必要性を活用し、スレッドのパラメーター化された名前をカスタマイズすることさえ可能にします。

29
Andreas

私は現在このようにやっています:

    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);
            }
        }
    });
37
/**
 * 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は現在のスレッドグループ内のスレッドの順序を表します。

10
MTSan

スレッドがスレッドプールによって管理されているときにスレッドの名前を変更するときは注意してください...望ましくない動作を回避するために、Runnable/Callableが終了したら、スレッド名が復元されることを確認する必要があります。

これを実装する1つの方法は、スレッドプールによって実行されるすべてのRunnable/Callableを、必要なすべてのクリーンアップを処理するデコレーターでラップすることです。

8
Shai

Springを使用している場合、 org.springframework.scheduling.concurrent.CustomizableThreadFactory を使用できます。

ExecutorService executorService = Executors.newCachedThreadPool(
                             new CustomizableThreadFactory("MyThreadNamePrefix"));
7

私はちょうどあなたが求めていることをしなければなりませんでした-私のスレッドグループに名前を提供します-したがって、Andeasの答えのおかげで、Executors $ DefaultThreadFactoryをコピーして、それを使用するクラスの内部クラスとして独自のThreadFactoryを作成しました、パラメータ「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);

質問をしてくれたuser381878と、答えてくれたAndreasに感謝します。

3
Eric Larson

Executorサービスを取得するための匿名のThreadFactoryを作成するだけです。 ThreadFactoryは、次のようにスレッドの名前を提供できます:「スレッドA」または「スレッドB」(例を参照)。

次に、さまざまなexecutorサービスを使用して呼び出し可能タスクを呼び出します。

クラスの例:

パブリッククラス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;
}

}

0
Nipin P

私が使用したアプローチの1つであり、私の場合は、1つのクラスで制御されたデータを並行してフェッチする先物がいくつかありました。私は多くの仕事を提出し、先物を取り戻します。ジョブ名として値を持つマップに未来を保存します。その後、すべての先物でタイムアウトを設定してgetを実行すると、マップからジョブの名前がわかります。それはおそらく最も柔軟な方法ではありませんが、私の状況では機能しました。

0