3

如何将可调用线程作为守护线程?

这是我正在尝试的。我正在尝试执行一组线程,其中一个线程没有完成并进入无限循环。它所做的是,即使所有代码语句都已执行,程序的主线程也不会终止。之后主线程进入挂起模式。

这是相同的代码片段。

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

如何将可调用线程作为守护线程?

您需要使用一个 newThreadFactory来创建守护线程。在此处查看此答案:Java 中的执行程序和守护程序

默认情况下,执行程序在构建池时创建非守护线程。但是你可以注入你自己的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

仅设置Thread由 to 守护程序创建的 sExecutorService无济于事(尽管您确实需要这样做)。您可以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#shutdownNowFuture#cancel(true)将帮助您的中断,因为您的Callable代码没有执行阻塞操作或以其他方式检查中断。

从这里,您有两个选择:

  1. 使用Future#getlong timeout参数的形式。
  2. 用于Future#isDone确定Future#get方法在实际调用之前是否有要返回的值Future#get
于 2012-04-05T17:45:13.583 回答
0

感谢蒂姆的详细解释。但是,您提出的解决方案并未解决问题。问题是由于线程进入了无限循环,它不会检查任何线程中断,因此不会终止。

对于我的场景,无限循环不是一个很好的例子,但我们试图完成的是我们正在执行一个执行时间过长的正则表达式,并且在 matcher.find() 调用之后检查中断。因为 find() 没有在规定的时间内返回,而且 find() 方法也没有检查线程中断,所以我们面临着悬空线程的问题。最后,从这个url实现 InterruptableCharSequence并让它工作。

于 2012-04-06T13:18:44.393 回答