Como posso terminar as tarefas que atingiram o tempo limite no multithreading?
Preciso criar uma biblioteca na qual terei métodos síncronos e assíncronos.
executeSynchronous()
- espera até que eu tenha um resultado, retorna o resultado.executeAsynchronous()
- retorna um futuro imediatamente, que pode ser processado depois que outras coisas forem feitas, se necessário.Lógica principal da minha biblioteca
O cliente usará nossa biblioteca e chamará passandoDataKey
objeto construtor. Em seguida, construiremos um URL usando esseDataKey
objeto e faça uma chamada de cliente HTTP para esse URL, executando-o e depois que recebermos a resposta novamente como uma String JSON, enviaremos essa String JSON de volta ao nosso cliente, criandoDataResponse
objeto. Algum cliente ligaráexecuteSynchronous()
e alguns podem ligarexecuteAsynchronous()
é por isso que preciso fornecer dois métodos separadamente na minha biblioteca.
Interface:
public interface Client {
// for synchronous
public DataResponse executeSynchronous(DataKey key);
// for asynchronous
public Future<DataResponse> executeAsynchronous(DataKey key);
}
E então eu tenho o meuDataClient
que implementa o acimaClient
interface:
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate();
private ExecutorService executor = Executors.newFixedThreadPool(10);
// for synchronous call
@Override
public DataResponse executeSynchronous(DataKey key) {
DataResponse dataResponse = null;
Future<DataResponse> future = null;
try {
future = executeAsynchronous(key);
dataResponse = future.get(key.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, key);
dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
// does this look right the way I am doing it?
future.cancel(true); // terminating tasks that have timed out.
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
//for asynchronous call
@Override
public Future<DataResponse> executeAsynchronous(DataKey key) {
Future<DataResponse> future = null;
try {
Task task = new Task(key, restTemplate);
future = executor.submit(task);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
}
return future;
}
}
Classe simples que executará a tarefa real:
public class Task implements Callable<DataResponse> {
private DataKey key;
private RestTemplate restTemplate;
public Task(DataKey key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
@Override
public DataResponse call() {
DataResponse dataResponse = null;
String response = null;
try {
String url = createURL();
response = restTemplate.getForObject(url, String.class);
// it is a successful response
dataResponse = new DataResponse(response, DataErrorEnum.NONE, DataStatusEnum.SUCCESS);
} catch (RestClientException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.SERVER_DOWN, key);
dataResponse = new DataResponse(null, DataErrorEnum.SERVER_DOWN, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
// create a URL by using key object
private String createURL() {
String url = somecode;
return url;
}
}
Declaração do problema: -
Quando comecei a trabalhar nesta solução, não estava finalizando as tarefas que atingiram o tempo limite. Eu estava relatando o tempo limite para o cliente, mas a tarefa continua em execução no pool de threads (ocupando potencialmente um dos meus 10 threads limitados por um longo tempo). Pesquisei on-line e descobri que posso cancelar minhas tarefas que atingiram o tempo limite usandocancel
emfuture
como mostrado abaixo -
future.cancel(true);
Mas eu queria ter certeza, parece correto do jeito que estou fazendo no meuexecuteSynchronous
método para cancelar as tarefas que atingiram o tempo limite?
Desde que eu estou ligandocancel()
noFuture
o que impedirá a execução se as tarefas ainda estiverem na fila, por isso não tenho certeza do que estou fazendo ou não? Qual é a abordagem correta para fazer isso?
Se existe uma maneira melhor, alguém pode dar um exemplo disso?