簡體   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