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

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

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

这是相同的代码片段。

public class MyThread implements Callable { 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> result = null; String parsedValue = null; try { executor = Executors.newSingleThreadExecutor(); List threads = new ArrayList(); 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 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中悬空线程的问题我要理解的是,我必须将我的线程作为守护线程。

您需要使用创建守护程序线程的新ThreadFactory 。 在这里看到这个答案:

Java中的Executor和Daemon

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

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

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

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

只是将ExecutorService创建的Thread设置为守护进程将无济于事(尽管您确实需要这样做)。 您可以将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 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的forms,它需要一个long timeout参数。
  2. 使用Future#isDone确定Future#get方法是否具有在实际调用Future#get之前返回的值。

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

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