Ich habe eine Aufzeichnungsklasse, die alle n Millisekunden nach Werten aus einer Datenquelle fragt. Das Ganze soll asynchron laufen und eine Sammlung zurückgeben, die die aufgezeichneten Daten enthält.Eine Zukunft abbrechen und trotzdem den Rückgabewert abrufen
Meine Idee war ein ExecutorService mit einem einzigen Thread und einem Callable, das die Datenabfrage durchführt. Das Callable soll unterbrochen werden, damit der Caller nicht auf Thread.sleep
Calls warten muss. He Callable Interrupt ich rufe Future.cancel(true)
über die Zukunft wieder von der ExecutorService:
class Recorder {
private DataSource source;
private ExecutorService executor;
private Future<List<MyData>> dataFuture;
private class FixedPollRateCallable {
private DataSource source;
private long pollrate;
public FixedPollrateCallable(DataSource source, long pollrate) {
this.source = source;
this.pollrate = pollrate;
}
public List<MyData> call() throws Exception {
List<MyData> dataList = new ArrayList<>();
while(!Thread.currentThread().isInterrupted()) {
dataList.add(source.getData());
try {
Thread.sleep(pollrate);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
return dataList;
}
}
public Recorder(DataSource source) {
this.source = source;
this.executor = Executors.newSingleThreadExecutor();
}
public void startRecording(long pollrate) {
if(dataFuture != null && !dataFuture.isDone())
throw new RecordingException();
dataFuture = executor.submit(new FixedPollRateCallable(source, pollrate);
}
public void stopRecording() {
dataFuture.cancel(true);
}
public List<MyData> getRecordedData() throws InterruptedException, ExecutionException {
return dataFuture.get();
}
}
Aber wenn das Ganze wie folgt nennen:
recorder.startRecording();
recorder.stopRecording();
recorder.getRecordedData();
Ich bekomme eine java.util.concurrent.CancellationException
auf dem recorder.getRecordedData()
Anruf.
Ich denke, dass neben dem Unterbrechen des Threads, cancel(true)
setzt auch ein Abbruch-Flag, so dass Anrufe an Future.get()
wird immer scheitern.
Gibt es eine Möglichkeit, oder wissen Sie über eine bessere Alternative, die es mir erlaubt, einen Thread zu unterbrechen, Thread.sleep()
ausbrechen und immer noch einen Wert zurückgeben können?
Ich habe nie so darüber nachgedacht. Können Sie mir ein paar Hinweise geben, was eine "sichere Senke" ist? Ich bin neu in der gleichzeitigen Programmierung in Java und es scheint, als ob eine selbstgemachte Lösung fast immer aufgrund einer Race-Bedingung oder eines Caching-Fehlers fehlschlägt. –
Siehe meine aktualisierte Antwort. – GhostCat
Ah, ich verstehe. Da die Recorder-Klasse sowieso eine Fassade für die zugrundeliegende Multithread-Verrücktheit ist, kann ich die List- "Senke" einkapseln, so dass es sicher ist, sie zu erhalten, nachdem die poll-callable (oder runnable in diesem Fall) abgebrochen wurde. Vielen Dank! –