补齐异步取消终态语义

This commit is contained in:
张家训
2026-08-01 17:29:03 +08:00
parent cd1218b575
commit 7867304e07
8 changed files with 224 additions and 10 deletions
@@ -6,6 +6,7 @@ import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
@@ -45,16 +46,27 @@ public final class AsyncOperationController<T> {
try {
T result = task.execute(context);
uiDispatcher.accept(() -> {
publish(stateMachine.succeed(
cancellationRequested.get() ? "已停止" : "操作完成"));
publish(cancellationRequested.get()
? stateMachine.cancel()
: stateMachine.succeed("操作完成"));
running.set(false);
onSuccess.accept(result);
});
} catch (Throwable error) {
if (error instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
uiDispatcher.accept(() -> {
publish(stateMachine.fail(readableMessage(error)));
boolean cancelled = cancellationRequested.get()
&& (error instanceof CancellationException
|| error instanceof InterruptedException);
publish(cancelled
? stateMachine.cancel()
: stateMachine.fail(readableMessage(error)));
running.set(false);
onFailure.accept(error);
if (!cancelled) {
onFailure.accept(error);
}
});
}
});
@@ -80,7 +92,8 @@ public final class AsyncOperationController<T> {
private void prepareStart(String message) {
OperationState current = stateMachine.snapshot().state();
if (current == OperationState.SUCCEEDED || current == OperationState.FAILED) {
if (current == OperationState.SUCCEEDED || current == OperationState.FAILED
|| current == OperationState.CANCELLED) {
stateMachine.reset();
}
cancellationRequested.set(false);
@@ -4,6 +4,7 @@ public enum OperationState {
IDLE,
RUNNING,
CANCELLING,
CANCELLED,
SUCCEEDED,
FAILED
}
@@ -30,13 +30,19 @@ public final class OperationStateMachine {
return update(OperationState.SUCCEEDED, message, 1);
}
public synchronized OperationSnapshot cancel() {
requireState(OperationState.CANCELLING);
return update(OperationState.CANCELLED, "已取消", snapshot.progress());
}
public synchronized OperationSnapshot fail(String message) {
requireState(OperationState.RUNNING, OperationState.CANCELLING);
return update(OperationState.FAILED, message, snapshot.progress());
}
public synchronized OperationSnapshot reset() {
requireState(OperationState.SUCCEEDED, OperationState.FAILED);
requireState(OperationState.SUCCEEDED, OperationState.FAILED,
OperationState.CANCELLED);
snapshot = OperationSnapshot.idle();
return snapshot;
}
@@ -122,6 +122,7 @@ public final class OperationStatusPane extends HBox {
case IDLE -> "就绪";
case RUNNING -> "处理中…";
case CANCELLING -> "正在停止…";
case CANCELLED -> "已取消";
case SUCCEEDED -> "操作完成";
case FAILED -> "操作失败";
};