Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何锁定Java线程,以便在Platform.runLater完成之前锁定其他线程_Java_Multithreading_Javafx 8 - Fatal编程技术网

如何锁定Java线程,以便在Platform.runLater完成之前锁定其他线程

如何锁定Java线程,以便在Platform.runLater完成之前锁定其他线程,java,multithreading,javafx-8,Java,Multithreading,Javafx 8,在我的OSGi中,可以随时启动和停止基于OSGi的应用程序包。面向UI的捆绑包向“桌面”捆绑包注册javafx节点。必须使用Platform.runLater(),在JavaFXUI线程上操作UI,这将安排它在以后执行 我想确保一次只有一个呼叫者可以修改桌面。我使用了一个锁和一个条件来实现这一点 public class DesktopContent implements ContentManager { private final Pane desktop; private final

在我的OSGi中,可以随时启动和停止基于OSGi的应用程序包。面向UI的捆绑包向“桌面”捆绑包注册javafx节点。必须使用
Platform.runLater()
,在JavaFXUI线程上操作UI,这将安排它在以后执行

我想确保一次只有一个呼叫者可以修改桌面。我使用了一个锁和一个条件来实现这一点

public class DesktopContent implements ContentManager {
  private final Pane desktop;
  private final AtomicReference<Node> weather = new AtomicReference<>();
  private final ReentrantLock lock = new ReentrantLock();

  @Override
  public void setWeatherWidget(Node node) {
    updateFX(() -> replaceNode(desktop.getChildren(), weather, node));
  }

  private void updateFX(Runnable runnable) {
    lock.lock();
    Condition condition = lock.newCondition();
    try {
        if (Platform.isFxApplicationThread()) {
            runnable.run();
        } else {
            updateFX(runnable, condition);
            condition.await();
        } 
    } catch (InterruptedException e) {
        logger.log(Level.WARNING, "While waiting for 'updating' condition", e);
    } finally {
        lock.unlock();
    }
  }

  private void updateFX(Runnable runnable, Condition condition) {
    Platform.runLater(() -> {
        lock.lock();
        try {
            runnable.run();
        } finally {
            condition.signal();
            lock.unlock();
        }
    });
}

private void replaceNode(List<Node> children, AtomicReference<Node> current, Node newNode) {
    SequentialTransition st = new SequentialTransition();
    ObservableList<Animation> transformations = st.getChildren();
    Node oldNode = current.getAndSet(newNode);

    if (oldNode != null) {
        FadeTransition ft = new FadeTransition(Duration.millis(350), oldNode);
        ft.setToValue(0d);
        ft.setOnFinished(e -> children.remove(oldNode));
        transformations.add(ft);
    }

    if (newNode != null) {
        newNode.setLayoutX(100d);
        newNode.setLayoutY(100d);
        FadeTransition ft = new FadeTransition(Duration.millis(350), newNode);
        ft.setFromValue(0d);
        ft.setToValue(1d);
        children.add(newNode);
        transformations.add(ft);
    }

    st.play();

}
公共类DesktopContent实现ContentManager{
私人最终版桌面;
私有最终原子参考天气=新原子参考();
private final ReentrantLock lock=new ReentrantLock();
@凌驾
公共void setWeatherWidget(节点){
updateFX(()->replaceNode(desktop.getChildren(),weather,node));
}
私有void updateFX(可运行可运行){
lock.lock();
Condition Condition=lock.newCondition();
试一试{
if(Platform.isFxApplicationThread()){
runnable.run();
}否则{
updateFX(可运行,条件);
条件wait();
} 
}捕捉(中断异常e){
logger.log(Level.WARNING,“在等待‘更新’条件时”,e);
}最后{
lock.unlock();
}
}
私有void updateFX(可运行,可运行,条件){
Platform.runLater(()->{
lock.lock();
试一试{
runnable.run();
}最后{
条件。信号();
lock.unlock();
}
});
}
私有void replaceNode(列出子节点、原子引用当前节点、节点newNode){
顺序转换st=新的顺序转换();
ObservableList transformations=st.getChildren();
Node oldNode=current.getAndSet(newNode);
if(oldNode!=null){
FadeTransition ft=新的FadeTransition(持续时间.毫秒(350),旧节点);
ft.setToValue(0d);
ft.setOnFinished(e->children.remove(oldNode));
添加(ft);
}
if(newNode!=null){
newNode.setLayoutX(100d);
newNode.setLayoutY(100d);
FadeTransition ft=新的FadeTransition(持续时间.毫秒(350),新节点);
ft.setFromValue(0d);
ft.setToValue(1d);
添加(newNode);
添加(ft);
}
圣普拉();
}
}

我不确定这是否正确。如果调用者不在应用程序线程上,框架将安排runnable的执行,调用者将等待直到满足条件

但是,如果同时有人调用setWeatherWidget,我想它会很高兴地被授予锁,安排另一个
稍后运行
。这意味着我完全可以跳过任何锁定


如何使用锁正确处理此问题?引入另一个“全局”锁?或者这是过度的工程设计,所有这些锁定业务都是不必要的?

我认为您可以做到这一点,而不必涉及锁、条件等较低级别的细节。本质上,您希望对
setWeatherWidget
单线程(一次只能调用一个)进行所有调用,当然,要确保必须在FX应用程序线程上执行的代码已经完成。关键是FX应用程序线程已经是单个线程:因此,您可以通过向FX应用程序线程发送请求并阻塞直到这些请求完成来实现这一点:

public class DesktopContent implements ContentManager {
    private final Pane desktop;
    private final AtomicReference<Node> weather = new AtomicReference<>();

    @Override
    public void setWeatherWidget(Node node) {
        updateFX(() -> replaceNode(desktop.getChildren(), weather, node));
    }

    private void updateFX(Runnable runnable) {
        try {
            if (Platform.isFxApplicationThread()) {
                runnable.run();
            } else {
                FutureTask<Void> task = new FutureTask<>(runnable, null);
                Platform.runLater(task);
                // block until task completes:
                task.get();
            } 
        } catch (InterruptedException e) {
            logger.log(Level.WARNING, "While waiting for 'updating' condition", e);
        }
    }

    private void replaceNode(List<Node> children, AtomicReference<Node> current, Node newNode) {
        SequentialTransition st = new SequentialTransition();
        ObservableList<Animation> transformations = st.getChildren();
        Node oldNode = current.getAndSet(newNode);

        if (oldNode != null) {
            FadeTransition ft = new FadeTransition(Duration.millis(350), oldNode);
            ft.setToValue(0d);
            ft.setOnFinished(e -> children.remove(oldNode));
            transformations.add(ft);
        }

        if (newNode != null) {
            newNode.setLayoutX(100d);
            newNode.setLayoutY(100d);
            FadeTransition ft = new FadeTransition(Duration.millis(350), newNode);
            ft.setFromValue(0d);
            ft.setToValue(1d);
            children.add(newNode);
            transformations.add(ft);
        }

        st.play();

    }

}
公共类DesktopContent实现ContentManager{
私人最终版桌面;
私有最终原子参考天气=新原子参考();
@凌驾
公共void setWeatherWidget(节点){
updateFX(()->replaceNode(desktop.getChildren(),weather,node));
}
私有void updateFX(可运行可运行){
试一试{
if(Platform.isFxApplicationThread()){
runnable.run();
}否则{
FutureTask任务=新的FutureTask(可运行,空);
Platform.runLater(任务);
//阻止,直到任务完成:
task.get();
} 
}捕捉(中断异常e){
logger.log(Level.WARNING,“在等待‘更新’条件时”,e);
}
}
私有void replaceNode(列出子节点、原子引用当前节点、节点newNode){
顺序转换st=新的顺序转换();
ObservableList transformations=st.getChildren();
Node oldNode=current.getAndSet(newNode);
if(oldNode!=null){
FadeTransition ft=新的FadeTransition(持续时间.毫秒(350),旧节点);
ft.setToValue(0d);
ft.setOnFinished(e->children.remove(oldNode));
添加(ft);
}
if(newNode!=null){
newNode.setLayoutX(100d);
newNode.setLayoutY(100d);
FadeTransition ft=新的FadeTransition(持续时间.毫秒(350),新节点);
ft.setFromValue(0d);
ft.setToValue(1d);
添加(newNode);
添加(ft);
}
圣普拉();
}
}

我通常使用
CountDownLatch
而不是条件,因为它避免了一次竞争:
signal()
可以在
wait()
之前调用。除此之外,我并不完全明白你想要实现什么。Runnables在一个线程中执行,因此不能并发执行,从而保证“一次只有一个调用者可以修改桌面”,而不需要任何锁定。@SergeyTachenov在
wait()
之前不可能调用
signal()
。在执行runLater时,第一个updateFX方法已经持有锁,因此除非第一个方法执行
wait()
,否则runLater无法获得锁。(但是使用CountDownLatch会使代码更短。)@VGR,你说得对。我被纠正了。我见过