简化 Task (#5365)

This commit is contained in:
Glavo
2026-02-01 19:10:01 +08:00
committed by GitHub
parent c45cd74b67
commit c1d0bb973a
4 changed files with 115 additions and 98 deletions

View File

@@ -326,8 +326,7 @@ public final class TaskListPane extends StackPane {
if (prevStageNodeRef != null && (prevStageNode = prevStageNodeRef.get()) != null) if (prevStageNodeRef != null && (prevStageNode = prevStageNodeRef.get()) != null)
prevStageNode.status.removeListener(statusChangeListener); prevStageNode.status.removeListener(statusChangeListener);
if (item instanceof ProgressListNode) { if (item instanceof ProgressListNode progressListNode) {
var progressListNode = (ProgressListNode) item;
title.setText(progressListNode.title); title.setText(progressListNode.title);
message.textProperty().bind(progressListNode.message); message.textProperty().bind(progressListNode.message);
bar.progressProperty().bind(progressListNode.progress); bar.progressProperty().bind(progressListNode.progress);
@@ -336,8 +335,7 @@ public final class TaskListPane extends StackPane {
pane.setLeft(null); pane.setLeft(null);
pane.setRight(message); pane.setRight(message);
pane.setBottom(bar); pane.setBottom(bar);
} else if (item instanceof StageNode) { } else if (item instanceof StageNode stageNode) {
var stageNode = (StageNode) item;
title.textProperty().bind(stageNode.title); title.textProperty().bind(stageNode.title);
message.setText(""); message.setText("");
bar.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS); bar.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
@@ -493,12 +491,10 @@ public final class TaskListPane extends StackPane {
private ProgressListNode(Task<?> task) { private ProgressListNode(Task<?> task) {
this.title = task.getName(); this.title = task.getName();
message.bind(task.messageProperty());
progress.bind(task.progressProperty()); progress.bind(task.progressProperty());
} }
public void unbind() { public void unbind() {
message.unbind();
progress.unbind(); progress.unbind();
} }

View File

@@ -92,7 +92,7 @@ public final class AsyncTaskExecutor extends TaskExecutor {
throw new IllegalStateException("Cannot cancel a not started TaskExecutor"); throw new IllegalStateException("Cannot cancel a not started TaskExecutor");
} }
cancelled.set(true); cancelled = true;
} }
private CompletableFuture<?> executeTasksExceptionally(Task<?> parentTask, Collection<? extends Task<?>> tasks) { private CompletableFuture<?> executeTasksExceptionally(Task<?> parentTask, Collection<? extends Task<?>> tasks) {
@@ -101,8 +101,6 @@ public final class AsyncTaskExecutor extends TaskExecutor {
return CompletableFuture.completedFuture(null) return CompletableFuture.completedFuture(null)
.thenComposeAsync(unused -> { .thenComposeAsync(unused -> {
totTask.addAndGet(tasks.size());
if (isCancelled()) { if (isCancelled()) {
for (Task<?> task : tasks) task.setException(new CancellationException()); for (Task<?> task : tasks) task.setException(new CancellationException());
return CompletableFuture.runAsync(this::checkCancellation); return CompletableFuture.runAsync(this::checkCancellation);
@@ -164,7 +162,7 @@ public final class AsyncTaskExecutor extends TaskExecutor {
} }
task.setResult(result); task.setResult(result);
task.onDone().fireEvent(new TaskEvent(this, task, false)); task.fireDoneEvent(this, false);
taskListeners.forEach(it -> it.onFinished(task)); taskListeners.forEach(it -> it.onFinished(task));
task.setState(Task.TaskState.SUCCEEDED); task.setState(Task.TaskState.SUCCEEDED);
@@ -173,14 +171,13 @@ public final class AsyncTaskExecutor extends TaskExecutor {
}) })
.exceptionally(throwable -> { .exceptionally(throwable -> {
Throwable resolved = resolveException(throwable); Throwable resolved = resolveException(throwable);
if (resolved instanceof Exception) { if (resolved instanceof Exception e) {
Exception e = (Exception) resolved;
if (e instanceof InterruptedException || e instanceof CancellationException) { if (e instanceof InterruptedException || e instanceof CancellationException) {
task.setException(null); task.setException(null);
if (task.getSignificance().shouldLog()) { if (task.getSignificance().shouldLog()) {
LOG.trace("Task aborted: " + task.getName()); LOG.trace("Task aborted: " + task.getName());
} }
task.onDone().fireEvent(new TaskEvent(this, task, true)); task.fireDoneEvent(this, true);
taskListeners.forEach(it -> it.onFailed(task, e)); taskListeners.forEach(it -> it.onFailed(task, e));
} else { } else {
task.setException(e); task.setException(e);
@@ -188,7 +185,7 @@ public final class AsyncTaskExecutor extends TaskExecutor {
if (task.getSignificance().shouldLog()) { if (task.getSignificance().shouldLog()) {
LOG.trace("Task failed: " + task.getName(), e); LOG.trace("Task failed: " + task.getName(), e);
} }
task.onDone().fireEvent(new TaskEvent(this, task, true)); task.fireDoneEvent(this, true);
taskListeners.forEach(it -> it.onFailed(task, e)); taskListeners.forEach(it -> it.onFailed(task, e));
} }
@@ -278,7 +275,7 @@ public final class AsyncTaskExecutor extends TaskExecutor {
LOG.trace("Task finished: " + task.getName()); LOG.trace("Task finished: " + task.getName());
} }
task.onDone().fireEvent(new TaskEvent(this, task, false)); task.fireDoneEvent(this, false);
taskListeners.forEach(it -> it.onFinished(task)); taskListeners.forEach(it -> it.onFinished(task));
task.setState(Task.TaskState.SUCCEEDED); task.setState(Task.TaskState.SUCCEEDED);
@@ -300,7 +297,7 @@ public final class AsyncTaskExecutor extends TaskExecutor {
LOG.trace("Task failed: " + task.getName(), e); LOG.trace("Task failed: " + task.getName(), e);
} }
} }
task.onDone().fireEvent(new TaskEvent(this, task, true)); task.fireDoneEvent(this, true);
taskListeners.forEach(it -> it.onFailed(task, e)); taskListeners.forEach(it -> it.onFailed(task, e));
task.setState(Task.TaskState.FAILED); task.setState(Task.TaskState.FAILED);
@@ -311,8 +308,8 @@ public final class AsyncTaskExecutor extends TaskExecutor {
} }
private <T> CompletableFuture<T> executeTask(Task<?> parentTask, Task<T> task) { private <T> CompletableFuture<T> executeTask(Task<?> parentTask, Task<T> task) {
if (task instanceof CompletableFutureTask<?>) { if (task instanceof CompletableFutureTask<T> completableFutureTask) {
return executeCompletableFutureTask(parentTask, (CompletableFutureTask<T>) task); return executeCompletableFutureTask(parentTask, completableFutureTask);
} else { } else {
return executeNormalTask(parentTask, task); return executeNormalTask(parentTask, task);
} }

View File

@@ -18,18 +18,18 @@
package org.jackhuang.hmcl.task; package org.jackhuang.hmcl.task;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import org.jackhuang.hmcl.event.EventManager; import org.jackhuang.hmcl.event.EventManager;
import org.jackhuang.hmcl.util.InvocationDispatcher;
import org.jackhuang.hmcl.util.function.ExceptionalConsumer; import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
import org.jackhuang.hmcl.util.function.ExceptionalFunction; import org.jackhuang.hmcl.util.function.ExceptionalFunction;
import org.jackhuang.hmcl.util.function.ExceptionalRunnable; import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
import org.jackhuang.hmcl.util.function.ExceptionalSupplier; import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.*; import java.util.*;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -47,8 +47,6 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
*/ */
public abstract class Task<T> { public abstract class Task<T> {
private final EventManager<TaskEvent> onDone = new EventManager<>();
/** /**
* True if not logging when executing this task. * True if not logging when executing this task.
*/ */
@@ -64,9 +62,9 @@ public abstract class Task<T> {
} }
// cancel // cancel
private Supplier<Boolean> cancelled; private BooleanSupplier cancelled;
final void setCancelled(Supplier<Boolean> cancelled) { final void setCancelled(BooleanSupplier cancelled) {
this.cancelled = cancelled; this.cancelled = cancelled;
} }
@@ -76,7 +74,7 @@ public abstract class Task<T> {
return true; return true;
} }
return cancelled != null ? cancelled.get() : false; return cancelled != null && cancelled.getAsBoolean();
} }
// stage // stage
@@ -92,6 +90,7 @@ public abstract class Task<T> {
/** /**
* You must initialize stage in constructor. * You must initialize stage in constructor.
*
* @param stage the stage * @param stage the stage
*/ */
protected final void setStage(String stage) { protected final void setStage(String stage) {
@@ -211,10 +210,10 @@ public abstract class Task<T> {
} }
// name // name
private String name = getClass().getName(); private String name;
public String getName() { public String getName() {
return name; return name != null ? name : getClass().getName();
} }
public Task<T> setName(String name) { public Task<T> setName(String name) {
@@ -236,7 +235,7 @@ public abstract class Task<T> {
/** /**
* Returns the result of this task. * Returns the result of this task.
* * <p>
* The result will be generated only if the execution is completed. * The result will be generated only if the execution is completed.
*/ */
public T getResult() { public T getResult() {
@@ -270,7 +269,8 @@ public abstract class Task<T> {
* @throws InterruptedException if current thread is interrupted * @throws InterruptedException if current thread is interrupted
* @see Thread#isInterrupted() * @see Thread#isInterrupted()
*/ */
public void preExecute() throws Exception {} public void preExecute() throws Exception {
}
/** /**
* @throws InterruptedException if current thread is interrupted * @throws InterruptedException if current thread is interrupted
@@ -284,7 +284,7 @@ public abstract class Task<T> {
/** /**
* This method will be called after dependency tasks terminated all together. * This method will be called after dependency tasks terminated all together.
* * <p>
* You can check whether dependencies succeed in this method by calling * You can check whether dependencies succeed in this method by calling
* {@link Task#isDependenciesSucceeded()} no matter when * {@link Task#isDependenciesSucceeded()} no matter when
* {@link Task#isRelyingOnDependencies()} returns true or false. * {@link Task#isRelyingOnDependencies()} returns true or false.
@@ -293,7 +293,8 @@ public abstract class Task<T> {
* @see Thread#isInterrupted() * @see Thread#isInterrupted()
* @see Task#isDependenciesSucceeded() * @see Task#isDependenciesSucceeded()
*/ */
public void postExecute() throws Exception {} public void postExecute() throws Exception {
}
/** /**
* The collection of sub-tasks that should execute **before** this task running. * The collection of sub-tasks that should execute **before** this task running.
@@ -310,44 +311,74 @@ public abstract class Task<T> {
return Collections.emptySet(); return Collections.emptySet();
} }
private volatile EventManager<TaskEvent> onDone;
public EventManager<TaskEvent> onDone() { public EventManager<TaskEvent> onDone() {
EventManager<TaskEvent> onDone = this.onDone;
if (onDone == null) {
synchronized (this) {
onDone = this.onDone;
if (onDone == null) {
this.onDone = onDone = new EventManager<>();
}
}
}
return onDone; return onDone;
} }
protected long getProgressInterval() { void fireDoneEvent(Object source, boolean failed) {
return 1000L; EventManager<TaskEvent> onDone = this.onDone;
if (onDone != null)
onDone.fireEvent(new TaskEvent(source, this, failed));
} }
private long lastTime = Long.MIN_VALUE; private final DoubleProperty progress = new SimpleDoubleProperty(this, "progress", -1);
private final ReadOnlyDoubleWrapper progress = new ReadOnlyDoubleWrapper(this, "progress", -1);
private final InvocationDispatcher<Double> progressUpdate = InvocationDispatcher.runOn(Platform::runLater, progress::set);
public ReadOnlyDoubleProperty progressProperty() { public ReadOnlyDoubleProperty progressProperty() {
return progress.getReadOnlyProperty(); return progress;
} }
private long lastUpdateProgressTime = 0L;
protected void updateProgress(long progress, long total) { protected void updateProgress(long progress, long total) {
updateProgress(1.0 * progress / total); updateProgress(1.0 * progress / total);
} }
protected void updateProgress(double progress) { protected void updateProgress(double progress) {
if (progress < 0 || progress > 1.0) if (progress < 0 || progress > 1.0 || Double.isNaN(progress))
throw new IllegalArgumentException("Progress is must between 0 and 1."); throw new IllegalArgumentException("Progress must be between 0 and 1.");
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (lastTime == Long.MIN_VALUE || now - lastTime >= getProgressInterval()) { if (progress == 1.0 || now - lastUpdateProgressTime >= 1000L) {
updateProgressImmediately(progress); updateProgressImmediately(progress);
lastTime = now; lastUpdateProgressTime = now;
} }
} }
protected void updateProgressImmediately(double progress) { //region Helpers for updateProgressImmediately
progressUpdate.accept(progress);
@SuppressWarnings("FieldMayBeFinal")
private volatile double pendingProgress = -1.0;
/// @see Task#pendingProgress
private static final VarHandle PENDING_PROGRESS_HANDLE;
static {
try {
PENDING_PROGRESS_HANDLE = MethodHandles.lookup()
.findVarHandle(Task.class, "pendingProgress", double.class);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
}
} }
//endregion updateProgressImmediately
private final ReadOnlyStringWrapper message = new ReadOnlyStringWrapper(this, "message", null); protected void updateProgressImmediately(double progress) {
// assert progress >= 0 && progress <= 1.0;
public final ReadOnlyStringProperty messageProperty() { if ((double) PENDING_PROGRESS_HANDLE.getAndSet(this, progress) == -1.0) {
return message.getReadOnlyProperty(); Platform.runLater(() -> this.progress.set((double) PENDING_PROGRESS_HANDLE.getAndSet(this, -1.0)));
}
} }
public final T run() throws Exception { public final T run() throws Exception {
@@ -359,16 +390,14 @@ public abstract class Task<T> {
execute(); execute();
for (Task<?> task : getDependencies()) for (Task<?> task : getDependencies())
doSubTask(task); doSubTask(task);
onDone.fireEvent(new TaskEvent(this, this, false)); fireDoneEvent(this, false);
return getResult(); return getResult();
} }
private void doSubTask(Task<?> task) throws Exception { private void doSubTask(Task<?> task) throws Exception {
message.bind(task.message);
progress.bind(task.progress); progress.bind(task.progress);
task.run(); task.run();
message.unbind();
progress.unbind(); progress.unbind();
} }
@@ -402,7 +431,7 @@ public abstract class Task<T> {
* normally, is executed using the default Executor, with this * normally, is executed using the default Executor, with this
* task's result as the argument to the supplied function. * task's result as the argument to the supplied function.
* *
* @param fn the function to use to compute the value of the returned Task * @param fn the function to use to compute the value of the returned Task
* @param <U> the function's return type * @param <U> the function's return type
* @return the new Task * @return the new Task
*/ */
@@ -416,8 +445,8 @@ public abstract class Task<T> {
* task's result as the argument to the supplied function. * task's result as the argument to the supplied function.
* *
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @param fn the function to use to compute the value of the returned Task * @param fn the function to use to compute the value of the returned Task
* @param <U> the function's return type * @param <U> the function's return type
* @return the new Task * @return the new Task
*/ */
public <U, E extends Exception> Task<U> thenApplyAsync(Executor executor, ExceptionalFunction<T, U, E> fn) { public <U, E extends Exception> Task<U> thenApplyAsync(Executor executor, ExceptionalFunction<T, U, E> fn) {
@@ -429,10 +458,10 @@ public abstract class Task<T> {
* normally, is executed using the supplied Executor, with this * normally, is executed using the supplied Executor, with this
* task's result as the argument to the supplied function. * task's result as the argument to the supplied function.
* *
* @param name the name of this new Task for displaying * @param name the name of this new Task for displaying
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @param fn the function to use to compute the value of the returned Task * @param fn the function to use to compute the value of the returned Task
* @param <U> the function's return type * @param <U> the function's return type
* @return the new Task * @return the new Task
*/ */
public <U, E extends Exception> Task<U> thenApplyAsync(String name, Executor executor, ExceptionalFunction<T, U, E> fn) { public <U, E extends Exception> Task<U> thenApplyAsync(String name, Executor executor, ExceptionalFunction<T, U, E> fn) {
@@ -445,7 +474,7 @@ public abstract class Task<T> {
* task's result as the argument to the supplied action. * task's result as the argument to the supplied action.
* *
* @param action the action to perform before completing the * @param action the action to perform before completing the
* returned Task * returned Task
* @return the new Task * @return the new Task
*/ */
public <E extends Exception> Task<Void> thenAcceptAsync(ExceptionalConsumer<T, E> action) { public <E extends Exception> Task<Void> thenAcceptAsync(ExceptionalConsumer<T, E> action) {
@@ -457,7 +486,7 @@ public abstract class Task<T> {
* normally, is executed using the supplied Executor, with this * normally, is executed using the supplied Executor, with this
* task's result as the argument to the supplied action. * task's result as the argument to the supplied action.
* *
* @param action the action to perform before completing the returned Task * @param action the action to perform before completing the returned Task
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @return the new Task * @return the new Task
*/ */
@@ -470,8 +499,8 @@ public abstract class Task<T> {
* normally, is executed using the supplied Executor, with this * normally, is executed using the supplied Executor, with this
* task's result as the argument to the supplied action. * task's result as the argument to the supplied action.
* *
* @param name the name of this new Task for displaying * @param name the name of this new Task for displaying
* @param action the action to perform before completing the returned Task * @param action the action to perform before completing the returned Task
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @return the new Task * @return the new Task
*/ */
@@ -487,7 +516,7 @@ public abstract class Task<T> {
* normally, executes the given action using the default Executor. * normally, executes the given action using the default Executor.
* *
* @param action the action to perform before completing the * @param action the action to perform before completing the
* returned Task * returned Task
* @return the new Task * @return the new Task
*/ */
public <E extends Exception> Task<Void> thenRunAsync(ExceptionalRunnable<E> action) { public <E extends Exception> Task<Void> thenRunAsync(ExceptionalRunnable<E> action) {
@@ -498,8 +527,8 @@ public abstract class Task<T> {
* Returns a new Task that, when this task completes * Returns a new Task that, when this task completes
* normally, executes the given action using the supplied Executor. * normally, executes the given action using the supplied Executor.
* *
* @param action the action to perform before completing the * @param action the action to perform before completing the
* returned Task * returned Task
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @return the new Task * @return the new Task
*/ */
@@ -511,9 +540,9 @@ public abstract class Task<T> {
* Returns a new Task that, when this task completes * Returns a new Task that, when this task completes
* normally, executes the given action using the supplied Executor. * normally, executes the given action using the supplied Executor.
* *
* @param name the name of this new Task for displaying * @param name the name of this new Task for displaying
* @param action the action to perform before completing the * @param action the action to perform before completing the
* returned Task * returned Task
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @return the new Task * @return the new Task
*/ */
@@ -528,7 +557,7 @@ public abstract class Task<T> {
* Returns a new Task that, when this task completes * Returns a new Task that, when this task completes
* normally, is executed using the default Executor. * normally, is executed using the default Executor.
* *
* @param fn the function to use to compute the value of the returned Task * @param fn the function to use to compute the value of the returned Task
* @param <U> the function's return type * @param <U> the function's return type
* @return the new Task * @return the new Task
*/ */
@@ -541,8 +570,8 @@ public abstract class Task<T> {
* normally, is executed using the default Executor. * normally, is executed using the default Executor.
* *
* @param name the name of this new Task for displaying * @param name the name of this new Task for displaying
* @param fn the function to use to compute the value of the returned Task * @param fn the function to use to compute the value of the returned Task
* @param <U> the function's return type * @param <U> the function's return type
* @return the new Task * @return the new Task
*/ */
public final <U> Task<U> thenSupplyAsync(String name, Callable<U> fn) { public final <U> Task<U> thenSupplyAsync(String name, Callable<U> fn) {
@@ -554,7 +583,7 @@ public abstract class Task<T> {
* normally, is executed. * normally, is executed.
* *
* @param other the another Task * @param other the another Task
* @param <U> the type of the returned Task's result * @param <U> the type of the returned Task's result
* @return the Task * @return the Task
*/ */
public final <U> Task<U> thenComposeAsync(Task<U> other) { public final <U> Task<U> thenComposeAsync(Task<U> other) {
@@ -565,7 +594,7 @@ public abstract class Task<T> {
* Returns a new Task that, when this task completes * Returns a new Task that, when this task completes
* normally, is executed. * normally, is executed.
* *
* @param fn the function returning a new Task * @param fn the function returning a new Task
* @param <U> the type of the returned Task's result * @param <U> the type of the returned Task's result
* @return the Task * @return the Task
*/ */
@@ -577,9 +606,9 @@ public abstract class Task<T> {
* Returns a new Task that, when this task completes * Returns a new Task that, when this task completes
* normally, is executed. * normally, is executed.
* *
* @param fn the function returning a new Task * @param fn the function returning a new Task
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @param <U> the type of the returned Task's result * @param <U> the type of the returned Task's result
* @return the Task * @return the Task
*/ */
public final <U> Task<U> thenComposeAsync(Executor executor, ExceptionalSupplier<Task<U>, ?> fn) { public final <U> Task<U> thenComposeAsync(Executor executor, ExceptionalSupplier<Task<U>, ?> fn) {
@@ -591,7 +620,7 @@ public abstract class Task<T> {
* normally, is executed with result of this task as the argument * normally, is executed with result of this task as the argument
* to the supplied function. * to the supplied function.
* *
* @param fn the function returning a new Task * @param fn the function returning a new Task
* @param <U> the type of the returned Task's result * @param <U> the type of the returned Task's result
* @return the Task * @return the Task
*/ */
@@ -604,9 +633,9 @@ public abstract class Task<T> {
* normally, is executed with result of this task as the argument * normally, is executed with result of this task as the argument
* to the supplied function. * to the supplied function.
* *
* @param fn the function returning a new Task * @param fn the function returning a new Task
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @param <U> the type of the returned Task's result * @param <U> the type of the returned Task's result
* @return the Task * @return the Task
*/ */
public <U, E extends Exception> Task<U> thenComposeAsync(Executor executor, ExceptionalFunction<T, Task<U>, E> fn) { public <U, E extends Exception> Task<U> thenComposeAsync(Executor executor, ExceptionalFunction<T, Task<U>, E> fn) {
@@ -626,7 +655,7 @@ public abstract class Task<T> {
* normally, executes the given action using the default Executor. * normally, executes the given action using the default Executor.
* *
* @param action the action to perform before completing the * @param action the action to perform before completing the
* returned Task * returned Task
* @return the new Task * @return the new Task
*/ */
public <E extends Exception> Task<Void> withRunAsync(ExceptionalRunnable<E> action) { public <E extends Exception> Task<Void> withRunAsync(ExceptionalRunnable<E> action) {
@@ -637,8 +666,8 @@ public abstract class Task<T> {
* Returns a new Task that, when this task completes * Returns a new Task that, when this task completes
* normally, executes the given action using the supplied Executor. * normally, executes the given action using the supplied Executor.
* *
* @param action the action to perform before completing the * @param action the action to perform before completing the
* returned Task * returned Task
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @return the new Task * @return the new Task
*/ */
@@ -650,9 +679,9 @@ public abstract class Task<T> {
* Returns a new Task that, when this task completes * Returns a new Task that, when this task completes
* normally, executes the given action using the supplied Executor. * normally, executes the given action using the supplied Executor.
* *
* @param name the name of this new Task for displaying * @param name the name of this new Task for displaying
* @param action the action to perform before completing the * @param action the action to perform before completing the
* returned Task * returned Task
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @return the new Task * @return the new Task
*/ */
@@ -690,7 +719,7 @@ public abstract class Task<T> {
* encounters an exception, then the returned task exceptionally completes * encounters an exception, then the returned task exceptionally completes
* with this exception unless this task also completed exceptionally. * with this exception unless this task also completed exceptionally.
* *
* @param action the action to perform * @param action the action to perform
* @param executor the executor to use for asynchronous execution * @param executor the executor to use for asynchronous execution
* @return the new Task * @return the new Task
*/ */
@@ -994,10 +1023,12 @@ public abstract class Task<T> {
FAILED FAILED
} }
@FunctionalInterface
public interface FinalizedCallback { public interface FinalizedCallback {
void execute(Exception exception) throws Exception; void execute(Exception exception) throws Exception;
} }
@FunctionalInterface
public interface FinalizedCallbackWithResult<T> { public interface FinalizedCallbackWithResult<T> {
void execute(T result, Exception exception) throws Exception; void execute(T result, Exception exception) throws Exception;
} }
@@ -1063,7 +1094,7 @@ public abstract class Task<T> {
/** /**
* A task that combines two tasks and make sure pred runs before succ. * A task that combines two tasks and make sure pred runs before succ.
* *
* @param fn a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred. * @param fn a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred.
* @param relyingOnDependents true if this task chain will be broken when task pred fails. * @param relyingOnDependents true if this task chain will be broken when task pred fails.
*/ */
UniCompose(ExceptionalSupplier<Task<U>, ?> fn, boolean relyingOnDependents) { UniCompose(ExceptionalSupplier<Task<U>, ?> fn, boolean relyingOnDependents) {
@@ -1073,7 +1104,7 @@ public abstract class Task<T> {
/** /**
* A task that combines two tasks and make sure pred runs before succ. * A task that combines two tasks and make sure pred runs before succ.
* *
* @param fn a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred. * @param fn a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred.
* @param relyingOnDependents true if this task chain will be broken when task pred fails. * @param relyingOnDependents true if this task chain will be broken when task pred fails.
*/ */
UniCompose(ExceptionalFunction<T, Task<U>, ?> fn, boolean relyingOnDependents) { UniCompose(ExceptionalFunction<T, Task<U>, ?> fn, boolean relyingOnDependents) {

View File

@@ -20,20 +20,17 @@ package org.jackhuang.hmcl.task;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class TaskExecutor { public abstract class TaskExecutor {
protected final Task<?> firstTask; protected final Task<?> firstTask;
protected final List<TaskListener> taskListeners = new ArrayList<>(); protected final List<TaskListener> taskListeners = new ArrayList<>(0);
protected final AtomicInteger totTask = new AtomicInteger(0); protected volatile boolean cancelled = false;
protected final AtomicBoolean cancelled = new AtomicBoolean(false);
protected Exception exception; protected Exception exception;
private final List<String> stages; private final List<String> stages;
public TaskExecutor(Task<?> task) { public TaskExecutor(Task<?> task) {
this.firstTask = task; this.firstTask = task;
this.stages = task instanceof Task.StagesHintTask ? ((Task<?>.StagesHintTask) task).getStages() : Collections.emptyList(); this.stages = task instanceof Task<?>.StagesHintTask hintTask ? hintTask.getStages() : Collections.emptyList();
} }
public void addTaskListener(TaskListener taskListener) { public void addTaskListener(TaskListener taskListener) {
@@ -59,11 +56,7 @@ public abstract class TaskExecutor {
public abstract void cancel(); public abstract void cancel();
public boolean isCancelled() { public boolean isCancelled() {
return cancelled.get(); return cancelled;
}
public int getTaskCount() {
return totTask.get();
} }
public List<String> getStages() { public List<String> getStages() {