将可调用线程作为守护进程

时间:2012-04-05 14:45:11

标签: java multithreading

如何将Callable线程作为守护线程?

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

以下是相同的代码段。

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

我之前关于Dangling threads in Java的问题我要理解的是,我必须将我的线程作为守护线程。

4 个答案:

答案 0 :(得分:7)

  

如何将Callable线程作为守护线程?

您需要使用创建守护程序线程的新ThreadFactory。请在此处查看此答案:Executor and Daemon in 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(真);

是的,这不起作用,因为一旦线程启动就无法设置守护进程标志。

答案 1 :(得分:4)

这不是为了守护进程Callable。实际上你想让执行线程成为守护进程。您可以通过这种方式创建线程,使其成为守护进程:

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

答案 2 :(得分:0)

仅将Thread创建的ExecutorService设置为守护进程无效(尽管您确实需要这样做)。您可以将ExecutorService Thread设置为守护程序,如下所示:

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#get参数的long timeout形式。
  2. 使用Future#isDone确定Future#get方法是否具有在实际调用Future#get之前返回的值。

答案 3 :(得分:0)

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

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