From 1ab414e702a959920833908d8975992fa0e52796 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sat, 18 Oct 2025 21:50:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20Task=20=E7=9A=84=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=8D=A0=E7=94=A8=20(#4694)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jackhuang/hmcl/task/Task.java | 5 ---- .../hmcl/util/InvocationDispatcher.java | 25 ++++++++++++++++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java index 96f6dbc25..0b0799ea2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java @@ -345,16 +345,11 @@ public abstract class Task { } private final ReadOnlyStringWrapper message = new ReadOnlyStringWrapper(this, "message", null); - private final InvocationDispatcher 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()); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/InvocationDispatcher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/InvocationDispatcher.java index a6cf8031b..cb3659116 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/InvocationDispatcher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/InvocationDispatcher.java @@ -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 implements Consumer { + 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 InvocationDispatcher runOn(Executor executor, Consumer action) { return new InvocationDispatcher<>(executor, action); @@ -35,7 +46,10 @@ public final class InvocationDispatcher implements Consumer { private final Executor executor; private final Consumer action; - private final AtomicReference> pendingArg = new AtomicReference<>(); + + /// @see #PENDING_ARG_HANDLE + @SuppressWarnings("unused") + private volatile Holder pendingArg; private InvocationDispatcher(Executor executor, Consumer action) { this.executor = executor; @@ -44,12 +58,15 @@ public final class InvocationDispatcher implements Consumer { @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) PENDING_ARG_HANDLE.getAndSet(this, (Holder) 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); }); } }