TimeoutException が発生すると JVM が終了しない
-
19-09-2019 - |
質問
このようなことを行う必要があるコードがあります
それぞれが何らかのメソッド (たとえば、execute()) を備えたクラスのリストがあります。各クラスでそのメソッドを呼び出す必要があり、各呼び出しには固定のタイムアウトがあります。ここで、クラスの実行メソッドの 1 つが正しく書かれていないため、タイムアウトが発生し、jvm が終了しません。こんな感じで教室を運営しています。
java ExecutorServiceTest execute TestClass1 TestClass2 TestClass3
コードの実行が完了しても jvm が終了しないのはなぜですか?
次の出力が得られます
In class 1
In Class 2
java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
at java.util.concurrent.FutureTask.get(Unknown Source)
at ExecutorServiceTest.main(ExecutorServiceTest.java:78)
java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
at java.util.concurrent.FutureTask.get(Unknown Source)
2 番目のクラスの実行がタイムアウトになり、その後、3 番目のクラスの実行もタイムアウトになります。3 番目のクラスの実行がタイムアウトになるのはなぜですか?
jvm は実行完了後に終了しません。理由は何ですか?また、なぜですか? TestClass3
タイムアウトを実行しますか?
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
class Task implements Callable<String> {
Object instance;
Method m;
Object[] input;
Task(Object instance, Method m, Object[] input) {
this.instance = instance;
this.m = m;
this.input = input;
}
public String call() {
String s = "initial";
try {
m.invoke(instance, input);
}
catch (RuntimeException e) {
}
catch (Exception e) {
}
finally {
}
return s;
}
}
public class ExecutorServiceTest {
public static void main(String[] args) {
String methodName = args[0];
String className;
List<Object> instanceList = new ArrayList<Object>();
for (int i=1;i<args.length;i++) {
className = args[i];
Object o = null;
try {
o = Class.forName(className).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
instanceList.add(o);
}
ExecutorService executor = Executors.newSingleThreadExecutor();
Iterator<Object> iter = instanceList.iterator();
while (iter.hasNext()) {
Object o = iter.next();
Method m = null;
try {
m = o.getClass().getDeclaredMethod(methodName, new Class[] {});
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Task t = new Task(o,m,new Object[]{});
Future<String> fut = executor.submit(t);
try {
fut.get(2,TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
executor.shutdown();
}
}
public class TestClass1 {
public void execute() {
System.out.println("In class 1");
}
}
public class TestClass2 {
public void execute() {
System.out.println("In class 2");
boolean b = true;
while (b) {
}
}
}
public class TestClass3 {
public void execute() {
System.out.println("In class 3");
}
}
解決
ExecutorService.shutdown()
実際には実行中のエグゼキュータ/スレッドは停止しません。 新しいタスクの受け入れを停止するようにサービスに指示するだけです:
void shutdown()
正常なシャットダウンを開始します。以前に送信されたタスクは実行されますが、新しいタスクは受け入れられません。すでにシャットダウンされている場合、呼び出しによる追加の効果はありません。
TestClass2 インスタンスは、 while(true)
決して止まらないループ。
ExecutorService をすぐに停止したい場合は、次を使用できます。 awaitTermination(long timeout, TimeUnit unit)
または shutdownNow()
.
他のヒント
あなたはexecutor.shutdown()
を呼び出すかThreadFactory
に渡された適切なExecutors.newSingleThreadExecutor()
を使用して(デーモンスレッドを作成する必要があります。