Wie kann ich Aufgaben beenden, bei denen im Multithreading eine Zeitüberschreitung aufgetreten ist?

Ich muss eine Bibliothek erstellen, in der ich synchrone und asynchrone Methoden verwenden kann.

executeSynchronous() - wartet, bis ich ein Ergebnis habe, gibt das Ergebnis zurück.executeAsynchronous() - gibt eine Zukunft sofort zurück, die bei Bedarf bearbeitet werden kann, nachdem andere Dinge erledigt wurden.

Core Logic meiner Bibliothek

Der Kunde wird unsere Bibliothek benutzen und sie durch Weitergeben von @ aufrufeDataKey Builder-Objekt. Wir werden dann eine URL erstellen, indem wir das @ benutzeDataKey object und rufen diesen URL über einen HTTP-Client auf, indem Sie ihn ausführen. Nachdem wir die Antwort als JSON-Zeichenfolge zurückerhalten haben, senden wir diese JSON-Zeichenfolge unverändert an unseren Kunden zurück, indem Sie @ erstelleDataResponse Objekt. Einige Kunden werden @ anrufexecuteSynchronous() und einige könnten @ anrufexecuteAsynchronous() Deshalb muss ich zwei Methoden separat in meiner Bibliothek bereitstellen.

Schnittstelle

public interface Client {

    // for synchronous
    public DataResponse executeSynchronous(DataKey key);

    // for asynchronous
    public Future<DataResponse> executeAsynchronous(DataKey key);
}

Und dann habe ich meinDataClient was das oben genannte implementiertClient 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;
    }
}

Einfache Klasse, die die eigentliche Aufgabe ausführt:

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;
    }
}

Problemstellung:

Als ich anfing, an dieser Lösung zu arbeiten, beendete ich die abgelaufenen Aufgaben nicht. Ich habe dem Client das Timeout gemeldet, aber die Task wird weiterhin im Thread-Pool ausgeführt (möglicherweise belegt sie einen meiner begrenzten 10 Threads für längere Zeit). Also habe ich online recherchiert und festgestellt, dass ich meine Aufgaben, die abgelaufen sind, mit @ stornieren kancancel auffuture Wie nachfolgend dargestellt

future.cancel(true);

Aber ich wollte sicherstellen, dass es so aussieht, wie ich es in meinem @ machexecuteSynchronous -Methode zum Abbrechen von Aufgaben mit Zeitüberschreitung?

Seit ich rufecancel() auf deFuture Was verhindert, dass es ausgeführt wird, wenn sich noch Aufgaben in der Warteschlange befinden und ich nicht sicher bin, ob meine Aufgaben richtig sind oder nicht? Was ist der richtige Ansatz dafür?

Wenn es einen besseren Weg gibt, kann jemand ein Beispiel dafür liefern?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage