[英]How to handle third-party Java code in a Task submitted to ExecutorService in case it has an infinite loop
假设我在提交给ExecutorService
的Task
调用了第三方Java库。
我相信第三方库不是恶意的,但是很少有机会出现编程错误,导致它陷入无限循环,如果是这种情况,我无法修复它以解决那些罕见的问题。场合。
处理此问题的最佳方法是什么,以便应用程序也不会卡住? shutdownNow()
是否足以处理这种情况?
有一个相关的问题在ExecutorService任务中停止无限循环,但这依赖于程序员协作并检测Thread.currentThread().isInterrupted()
以停止处理的能力,这是我不能依赖的。
(在我的例子中它是Jython代码;在早期版本的Jython中,解释器显然没有检查Thread.currentThread().isInterrupted()
,不确定它现在做什么......但我的问题对于任何第三方都是一般的Java代码。)
如果任务有一个无限循环,不检查线程中断状态,并且不使用抛出InterruptedException
的方法,则shutdownNow()
不会停止它。
不允许程序完成的简单示例:
public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(1);
e.submit(() -> { while (true); });
e.shutdownNow();
System.out.println("Main is finished but the app keeps running");
}
一种方法是将线程作为守护进程运行:
public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(1, r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
});
e.submit(() -> { while (true); });
e.shutdownNow();
System.out.println("Main is finished and the app can exit");
}
在我正确阅读了这个问题后,我将这组课程放在一起。 相对简单:一个Runnable连接到套接字发送输入并从辅助jvm检索调用不稳定库的输出。
如果在3次尝试后没有收到任何响应,则杀死次要的jvm。 但它可以重新启动。 辅助jvm有一个关闭插座的出口钩。
class SafetyValve implements Runnable{
PrintWriter out;
BufferedReader in;
Socket s = null;
AtomicBoolean flag;
SafetyValve(AtomicBoolean b){
flag = b;
}
@Override
public void run() {
try {
s = new Socket("localhost", 9000);
out = new PrintWriter(s.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
while (!Thread.currentThread().isInterrupted()){
flag.set(false);
out.print(0);
out.flush();
System.out.print(in.read());
flag.set(true);
}
} catch (Exception e) {
e.printStackTrace();
}
finally{
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
主/控制器类。 它使用Thread类进行控制
public class Switch {
public static void main(String[] args) {
try {
AtomicBoolean flag = new AtomicBoolean(false);
int counter = 0;
ProcessBuilder pb = ...
pb.directory(,,,);
Process p = pb.start();
SafetyValve sv = new SafetyValve(flag);
Thread t = new Thread(sv);
t.start();
while(t.getState() != Thread.State.RUNNABLE){
Thread.sleep(10);
}
while(true){
if (flag.get() == false){
if (++counter == 3){
while(t.getState() != Thread.State.TERMINATED){
p.destroyForcibly();
t.interrupt();
Thread.sleep(10);
}
break;
}
}
else
counter = 0;
Thread.sleep(100);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
辅助jvm具有标准服务器套接字实现:
class UnYielding{
int i = 0;
int returnInt(){
i++;
if (i > 2)
while(true);
return i;
}
}
class Hook extends Thread{
RunWild rw;
Hook(RunWild wr){
rw = wr;
}
public void run() {
try {
System.out.println("exit...");
System.out.flush();
rw.socket.close();
rw.server.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class RunWild {
ServerSocket server;
Socket socket;
RunWild(){
Runtime.getRuntime().addShutdownHook(new Hook(this));
}
public static void main(String[] args){
UnYielding u;
int i;
PrintWriter out;
BufferedReader in;
RunWild rw = new RunWild();
try {
rw.server = new ServerSocket(9000);
rw.socket = rw.server.accept();
out = new PrintWriter(rw.socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(rw.socket.getInputStream()));
u = new UnYielding();
while ((i = in.read()) != -1){
out.print(u.returnInt());
out.flush();
Thread.sleep(10);
System.out.print("waiting...");
System.out.flush();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
我已经在OS X上对1.8进行了测试,它按预期工作。 如果需要这个不稳定的类,这是一种方法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.