O JVM não sair quando TimeoutException ocorre
-
19-09-2019 - |
Pergunta
Eu tenho o código que precisa fazer algo como isto
Há uma lista de classes, cada uma com algum método (digamos execute ()). Eu preciso invocar esse método em cada classe e há um tempo limite fixo para cada invocação. Agora, um dos da classe executar método é mal escrito e resulta em um tempo limite devido a que a JVM não sair. Estou executando a classe como este.
java ExecutorServiceTest execute TestClass1 TestClass2 TestClass3
Por que a JVM não sair depois de completar a execução do código?
Eu recebo a seguinte saída
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)
O segundo da classe executam vezes fora e, depois disso, o terceiro da classe executar também expira. Por que a terceira classe de executar tempo?
A JVM não sair após a execução for concluída. Qual é a razão? Também porque é que o TestClass3
executar TimedOut?
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");
}
}
Solução
ExecutorService.shutdown()
na verdade não parar qualquer correndo executores / threads, apenas informa ao serviço de parar de aceitar novas tarefas :
void shutdown()
Iniciados um desligamento ordenado em que as tarefas previamente submetidos são executados, mas há novas tarefas serão aceitos. Invocation não tem efeito adicional se já encerrado.
Seu exemplo TestClass2 nunca vai parar de correr porque tem um loop while(true)
que nunca é interrompida.
Se você quiser parar o ExecutorService imediatamente, você pode usar awaitTermination(long timeout, TimeUnit unit)
ou shutdownNow()
.
Outras dicas
Você precisa chamar executor.shutdown()
ou criar uma linha daemon (usando ThreadFactory
apropriado passado para Executors.newSingleThreadExecutor()