繁体   English   中英

Javafx Apps在执行线程等待并通知时挂起

[英]Javafx Apps get hang when perform Thread wait and notify

我正在使用无限循环从我的应用程序播放一些动画,效果很好。 我需要在用户需要时等待我的线程,并在用户需要时再次启动。 为此,我通过单击我的根目录布局使用了等待并通知线程,首先单击使我的线程等待,然后单击使我的线程运行。 这也像我想要的那样。

我的问题是我快速点击,这意味着当我等待并立即发出通知时,我的应用程序会挂起。

那么我如何解决这个问题呢?

以下是我的代码:

public class AboutC implements Initializable {

    public VBox mainLayout;
    @FXML
    private
    Label nameLvl = new Label();
    @FXML
    private
    Label rollLvl = new Label();
    @FXML
    private
    Label batchLvl = new Label();
    @FXML
    private
    Label depLvl = new Label();
    @FXML
    private
    Label uniLvl = new Label();
    @FXML
    private Circle circle = new Circle();
    private int count = 0;
    private boolean run = true;
    private Thread thread;
    private Task task;
    private FadeTransition fd;
    private RotateTransition rt;
    private Timeline tm;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        ArrayList<AboutDevelopers> list = new ArrayList<>();
        list.add(....)

        fd = new FadeTransition(Duration.seconds(4), mainLayout);
        fd.setFromValue(0.2);
        fd.setToValue(1.0);
        fd.setCycleCount(2);

        rt = new RotateTransition(Duration.seconds(4), circle);
        rt.setByAngle(360);
        rt.setAutoReverse(true);
        rt.setCycleCount(2);

        KeyFrame keyFrame = new KeyFrame(Duration.seconds(4), new KeyValue(circle.radiusProperty(), 0));
        tm = new Timeline(keyFrame);
        tm.setCycleCount(2);
        tm.setAutoReverse(true);

        task = new Task<Void>() {
            @Override
            synchronized public Void call() throws Exception {
                int i = 0;
                while (true) {
                    if (run) {
                        Platform.runLater(() -> {
                            nameLvl.setText(list.get(count).getName());
                            rollLvl.setText("Roll: " + list.get(count).getRoll());
                            batchLvl.setText("Batch: " + list.get(count).getBatch());
                            depLvl.setText("Department: " + list.get(count).getDepartment());
                            uniLvl.setText(list.get(count).getUniversity());
                            circle.setFill(new ImagePattern(new Image(list.get(count).getImagePath())));

                            fd.play();
                            rt.play();
                            tm.play();

                            count++;
                            if (count >= list.size())
                                count = 0;
                        });
                        sleep(10000);
                    } else
                        wait();
                }
            }
        };
        thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }

    void setStage(Stage stage) {
        stage.setOnCloseRequest(event -> {
            thread.interrupt();
        });
    }

    public void playThread(){
        if (run) {
            run = false;
        } else {
            if(!run){
                synchronized (task) {
                    task.notify();
                }
            }
            run = true;
        }
    }
}
  1. run不是volatile并且被写入同步块的外部。 这意味着任务可能永远不会看到更新后的值。
  2. 使用Thread.sleep(10000)不会释放对Task的锁定,这意味着可能发生以下情况:
    1. 任务开始休眠
    2. playThread方法更改runfalse
    3. 再次调用playThread方法,并尝试在任务对象上获取一个锁,该任务仍然保持自身状态,导致调用线程被阻塞长达10秒

要解决这些问题,请仅从同步块修改run字段,并使用带有超时的wait而不是sleep

while (true) {
    if (run) {
        Platform.runLater(() -> {
            nameLvl.setText(list.get(count).getName());
            rollLvl.setText("Roll: " + list.get(count).getRoll());
            batchLvl.setText("Batch: " + list.get(count).getBatch());
            depLvl.setText("Department: " + list.get(count).getDepartment());
            uniLvl.setText(list.get(count).getUniversity());
            circle.setFill(new ImagePattern(new Image(list.get(count).getImagePath())));

            fd.play();
            rt.play();
            tm.play();

            count++;
            if (count >= list.size())
                count = 0;
        });
        wait(10000);
    } else
        wait();
}
public void playThread(){
    synchronized (task) {
        run = !run;
        if (run) {
            task.notify();
        }
    }
}

这意味着,开始和停止任务可能会加快更新频率。


选择:

使用ScheduledExecutorService定期安排更新:

// TODO: shut this down after you're done with it???
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(r -> {
    Thread t = new Thread(r);
    t.setDaemon(true);
    return t;
});

@Override
public void initialize(URL location, ResourceBundle resources) {
    ...
    startTask();
}

private final Runnable updateRunnable = () -> {
    Platform.runLater(() -> {
        nameLvl.setText(list.get(count).getName());
        rollLvl.setText("Roll: " + list.get(count).getRoll());
        batchLvl.setText("Batch: " + list.get(count).getBatch());
        depLvl.setText("Department: " + list.get(count).getDepartment());
        uniLvl.setText(list.get(count).getUniversity());
        circle.setFill(new ImagePattern(new Image(list.get(count).getImagePath())));

        fd.play();
        rt.play();
        tm.play();

        count++;
        if (count >= list.size())
            count = 0;
        }
    });
};

private ScheduledFuture scheduledFuture;

private void startTask() {
    scheduledFuture = executor.scheduleWithFixedDelay(updateRunnable, 0, 10000, TimeUnit.MILLISECONDS);
}

public void playThread() {
    if (scheduledFuture == null) {
        // nothing running currently
        startTask();
    } else {
        scheduledFuture.cancel();
        scheduledFuture = null;
    }
}

或者以更适合JavaFX的方式

Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(10), evt -> {

        nameLvl.setText(list.get(count).getName());
        rollLvl.setText("Roll: " + list.get(count).getRoll());
        batchLvl.setText("Batch: " + list.get(count).getBatch());
        depLvl.setText("Department: " + list.get(count).getDepartment());
        uniLvl.setText(list.get(count).getUniversity());
        circle.setFill(new ImagePattern(new Image(list.get(count).getImagePath())));

        fd.play();
        rt.play();
        tm.play();

        count++;
        if (count >= list.size())
            count = 0;
        }
    });

}));
timeline.setCycleCount(Animation.INDEFINITE);

timeline.play();
if (timeline.getStatus == Animation.Status.RUNNING) {
    timeline.stop();
} else {
    timeline.play();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM