[英]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.