以下是我编写的一些代码,用于以通用方式处理事件处理程序,该事件处理程序仅对任何JavaFX事件触发一次:
public final class OneShotEvent<T extends Event>
implements EventHandler<T>
{
private final AtomicBoolean triggered = new AtomicBoolean(false);
private final EventHandler<T> delegate;
public static <E extends Event> EventHandler<E> of(final EventHandler<E> delegate)
{
return new OneShotEvent<>(delegate);
}
private OneShotEvent(final EventHandler<T> delegate)
{
this.delegate = Objects.requireNonNull(delegate);
}
@Override
public void handle(final T event)
{
if (!triggered.getAndSet(true))
delegate.handle(event);
}
}
出于某种原因,我将triggered
改为AtomicBoolean
而不是普通boolean
。
在考虑之后,我认为这是过度的,因为事件处理程序将在JavaFX的“平台线程”上运行......或者他们不会? 因为如果是这种情况,那么一个简单的布尔就足够了......对吗?
答案 0 :(得分:3)
如果你知道调用是单线程或线程安全的,那么一个简单的布尔就足够了,不过你可以放弃它。
private EventHandler<T> delegate;
public void handle(T event) {
if (delegate != null)
delegate.handle(event);
delegate = null; // don't retain a delegate we don't need
}
答案 1 :(得分:2)
在考虑之后,我认为这是矫枉过正,因为事件处理程序将在&#34;平台线程上运行&#34; JavaFX ...或者他们不会吗?
是的,他们会:
答案 2 :(得分:0)
如果您确定事件处理程序在应用程序线程上运行,则您不需要关心线程安全。
但是,事件也可以在非应用程序线程上运行。 触发事件的线程也是运行事件处理程序的线程。
您可以使用以下代码进行演示,这些代码甚至无法启动应用程序线程:
public class EventThreadsTest {
public static void main(String[] args) {
Thread t = Thread.currentThread();
EventHandler handler = (evt) -> {
System.out.println("Application thread: " + Platform.isFxApplicationThread());
System.out.println("main thread: " + Thread.currentThread() == t);
};
Node target = new Pane();
target.setOnMouseClicked(handler);
target.fireEvent(new MouseEvent(MouseEvent.MOUSE_CLICKED, 0, 0, 0, 0, MouseButton.PRIMARY, 1, true, true, true, true, true, true, true, true, true, true, null));
}
}
输出:
Application thread: false
main thread: true
然而,由用户交互触发的Button.onAction
和Node.onMouseClicked
等UI事件在应用程序线程上运行。