繁体   English   中英

如何在提交给ExecutorService的Task中处理第三方Java代码,以防它具有无限循环

[英]How to handle third-party Java code in a Task submitted to ExecutorService in case it has an infinite loop

假设我在提交给ExecutorServiceTask调用了第三方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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM