3

Callableスレッドをデーモンスレッドにするにはどうすればよいですか?

これが私が試していることです。そのうちの1つが完了せず、無限ループに陥るスレッドのセットを実行しようとしています。すべてのコードステートメントが実行されても、プログラムのメインスレッドは終了しません。その後、メインスレッドはサスペンドモードになります。

これが同じのコードスニペットです。

public class MyThread implements Callable<String> {

    private int value;

    public MyThread(int value) {
        this.value = value;
    }

    @Override
    public String call() throws Exception {

        //Thread.currentThread().setDaemon(true);

        System.out.println("Executing - " + value);

        if (value == 4) {
            for (; ; );
        }

        return value + "";
    }
}

メインプログラム

public class ExecutorMain {

    public static String testing() {    
        ExecutorService executor = null;
        List<Future<String>> result = null;
        String parsedValue = null;
        try {
            executor = Executors.newSingleThreadExecutor();

            List<MyThread> threads = new ArrayList<MyThread>();

            for (int i = 1; i < 10; i++) {
                MyThread obj = new MyThread(i);
                threads.add(obj);
            }

            result = executor.invokeAll(threads, Long.valueOf("4000"), TimeUnit.MILLISECONDS);
            //result = executor.invokeAll(threads);

            for (Future<String> f : result) {
                try {
                    parsedValue = f.get();
                    System.out.println("Return Value - " + parsedValue);
                } catch (CancellationException e) {
                    System.out.println("Cancelled");
                    parsedValue = "";
                    f.cancel(true);
                }
            }

            executor.shutdownNow();
        } catch (Exception e) {
            System.out.println("Exception while running threads");
            e.printStackTrace();
        } finally {
            List executedThreads = executor.shutdownNow();

            System.out.println(executedThreads);

            for (Object o : executedThreads) {
                System.out.println(o.getClass());
            }
        }
        System.out.println("Exiting....");
        //System.exit(1);

        return "";
    }

    public static void main(String[] args) {
        testing();
    }
}

Javaのダングリングスレッドに関する以前の質問から理解したことは、スレッドをデーモンスレッドとして作成する必要があるということです。

4

4 に答える 4

8

Callable スレッドをデーモンスレッドとして作成するにはどうすればよいですか?

ThreadFactoryデーモン スレッドを作成する new を使用する必要があります。ここでこの回答を参照してください: Java の Executor と Daemon

デフォルトでは、executor はプールを構築するたびに非デーモン スレッドを作成します。ThreadFactoryただし、プールのスレッドを作成する独自のものを注入できます。

例えば:

executor = ExecutorService.newSingleThreadExecutor(new MyThreadFactory());

メソッドをThreadFactory実装します。newThread

Thread newThread(Runnable r)

上記にリンクした回答からコピーすると、次のように実装できます。

class MyThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
    }
}

あなたはあなたの質問で言及しました:

//Thread.currentThread().setDaemon(true);

ええ、スレッドが開始されるとデーモンフラグを設定できないため、これは機能しません。

于 2012-04-05T14:46:28.183 に答える
4

Callableデーモンにすることではありません。実際には、実行スレッドをデーモンにしたいと考えています。この方法でスレッドを作成して、デーモンにすることができます。

executor = Executors.newSingleThreadExecutor(new ThreadFactory(){
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }        
});
于 2012-04-05T14:52:43.573 に答える
0

Threadtoデーモンによって作成されたを設定するだけでExecutorServiceは役に立ちません(ただし、これを行う必要があります)。ExecutorService Thread次のようにsをデーモンに設定できます。

executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }        
});

あなたが抱えている本当の問題は、このコードブロックにあります:

        for (Future<String> f : result) {
            try {
                parsedValue = f.get();
                System.out.println("Return Value - " + parsedValue);
            } catch (CancellationException e) {
                System.out.println("Cancelled");
                parsedValue = "";
                f.cancel(true);
            }
        }

        executor.shutdownNow();

より具体的には、このコードはここで永久にハングします:

parsedValue = f.get();

この理由は単純で、Future#get「必要に応じて計算が完了するのを待ってから、その結果を取得する」という方法ですが、無限ループにあるため、計算が完了することはありません。コードがブロッキング操作を実行したり、割り込みをチェックしたりしていないため、からの割り込みでさえ、ThreadPoolExecutor#shutdownNowまたはFuture#cancel(true)あなたを助けません。Callable

ここから、2つのオプションがあります。

  1. 引数Future#getを取るその形式を使用してください。long timeout
  2. を実際に呼び出す前に、メソッドに返す値があるFuture#isDoneかどうかを判別するために使用します。Future#getFuture#get
于 2012-04-05T17:45:13.583 に答える
0

詳細な説明をありがとうティム。ただし、提案されたソリューションは問題を解決しませんでした。問題は、スレッドが無限ループに陥ったため、スレッドの中断をチェックせず、終了しないことでした。

私のシナリオでは、無限ループは良い例ではありませんが、達成しようとしていたのは、実行に時間がかかりすぎる正規表現を実行していて、中断のチェックが matcher.find() 呼び出しの後であったことです。find() が規定の時間内に返されず、find() メソッドがスレッドの中断をチェックしないため、スレッドのダングリングの問題に直面していました。最後に、このURLから InterruptableCharSequence を実装し、機能させました。

于 2012-04-06T13:18:44.393 に答える