如何将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的问题我要理解的是,我必须将我的线程作为守护线程。
答案 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#shutdownNow
或Future#cancel(true)
的中断也不会对您有所帮助,因为您的Callable
代码并未执行阻止操作或检查中断。
从这里,您有两种选择:
Future#get
参数的long timeout
形式。Future#isDone
确定Future#get
方法是否具有在实际调用Future#get
之前返回的值。答案 3 :(得分:0)
感谢Tim的详细解释。但是,您提出的解决方案并未解决问题。问题是因为线程已进入无限循环,它不检查任何线程中断,因此不会终止。
对于我的场景,无限循环不是一个很好的例子,但我们试图完成的是我们正在执行一个执行时间太长的正则表达式,并且在matcher.find()调用之后检查中断。因为find()没有在规定的时间内返回,并且find()方法也没有检查线程中断,所以我们遇到了悬空线程问题。最后,从this url实施了InterruptableCharSequence并使其正常工作。