37

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

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

Thread thread = new Thread(runnable Task);
thread.setName("My Thread Name");

log4jロギングでスレッド名を使用しています。これは、トラブルシューティング時に非常に役立ちます。現在、コードをJava1.4からJava1.6に移行しています。私はこれを書きました(以下に与えられます)-しかし、私はこのスレッドに名前を付ける方法を知りません。

private final ExecutorService executorPool = Executors.newCachedThreadPool();
Future<String> result = executorPool.submit(callable Task);

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

4

8 に答える 8

44

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

    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);
            }
        }
    });
于 2011-02-28T13:42:35.020 に答える
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を提供します。

于 2010-07-12T09:07:38.517 に答える
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;
    }
}

これは、Java1.5.0の元の実装です。したがって、実際にはpool-x-threadという名前が付けられています。ここで、xは、現在のスレッドグループ内のスレッドの順序を表します。

于 2011-01-03T22:15:01.553 に答える
8

スレッドがスレッドプールによって管理されている場合、スレッドの名前を変更するときは注意が必要です。スレッドは実際にはさまざまなタスクで何度も再利用されており、名前を変更すると、ログ内のスレッド名が意味をなさない場合があります。 ...その望ましくない動作を回避するために、Runnable / Callableが終了したら、スレッド名が復元されていることを確認する必要があります。

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

于 2010-07-12T18:06:23.647 に答える
7

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

ExecutorService executorService = Executors.newCachedThreadPool(
                             new CustomizableThreadFactory("MyThreadNamePrefix"));
于 2014-02-16T09:04:45.520 に答える
3

スレッドグループに名前を付けるという、あなたが求めていることをしなければならなかったので、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に感謝します。

于 2014-01-20T16:41:26.103 に答える
0

エグゼキュータサービスを取得するための匿名のThreadFactoryを作成するだけです。ThreadFactoryは、「スレッドA」または「スレッドB」のようにスレッドの名前を指定できます(例を参照)。

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

クラスの例:

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

}

于 2016-06-08T09:10:23.280 に答える
0

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

于 2016-06-09T14:21:04.187 に答える