优化 Task 的资源占用 (#4694)

This commit is contained in:
Glavo
2025-10-18 21:50:23 +08:00
committed by GitHub
parent 16f6e89e45
commit 1ab414e702
2 changed files with 21 additions and 9 deletions

View File

@@ -345,16 +345,11 @@ public abstract class Task<T> {
}
private final ReadOnlyStringWrapper message = new ReadOnlyStringWrapper(this, "message", null);
private final InvocationDispatcher<String> messageUpdate = InvocationDispatcher.runOn(Platform::runLater, message::set);
public final ReadOnlyStringProperty messageProperty() {
return message.getReadOnlyProperty();
}
protected final void updateMessage(String newMessage) {
messageUpdate.accept(newMessage);
}
public final T run() throws Exception {
if (getSignificance().shouldLog())
LOG.trace("Executing task: " + getName());

View File

@@ -17,8 +17,9 @@
*/
package org.jackhuang.hmcl.util;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
/// When [#accept(T)] is called, this class invokes the handler on another thread.
@@ -28,6 +29,16 @@ import java.util.function.Consumer;
/// @author yushijinhun
public final class InvocationDispatcher<T> implements Consumer<T> {
private static final VarHandle PENDING_ARG_HANDLE;
static {
try {
PENDING_ARG_HANDLE = MethodHandles.lookup()
.findVarHandle(InvocationDispatcher.class, "pendingArg", Holder.class);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
}
}
/// @param executor The executor must dispatch all tasks to a single thread.
public static <T> InvocationDispatcher<T> runOn(Executor executor, Consumer<T> action) {
return new InvocationDispatcher<>(executor, action);
@@ -35,7 +46,10 @@ public final class InvocationDispatcher<T> implements Consumer<T> {
private final Executor executor;
private final Consumer<T> action;
private final AtomicReference<Holder<T>> pendingArg = new AtomicReference<>();
/// @see #PENDING_ARG_HANDLE
@SuppressWarnings("unused")
private volatile Holder<T> pendingArg;
private InvocationDispatcher(Executor executor, Consumer<T> action) {
this.executor = executor;
@@ -44,12 +58,15 @@ public final class InvocationDispatcher<T> implements Consumer<T> {
@Override
public void accept(T t) {
if (pendingArg.getAndSet(new Holder<>(t)) == null) {
if (PENDING_ARG_HANDLE.getAndSet(this, new Holder<>(t)) == null) {
executor.execute(() -> {
@SuppressWarnings("unchecked")
var holder = (Holder<T>) PENDING_ARG_HANDLE.getAndSet(this, (Holder<T>) null);
// If the executor supports multiple underlying threads,
// we need to add synchronization, but for now we can omit it :)
// synchronized (InvocationDispatcher.this)
action.accept(pendingArg.getAndSet(null).value);
action.accept(holder.value);
});
}
}