我正在使用无限循环从我的应用程序播放一些动画,效果很好。我需要在用户需要时等待我的线程,并在用户需要时再次启动。为此,我通过单击我的根布局使用等待和通知线程,首先单击使我的线程等待,然后第二次单击使我的线程运行。这也像我想要的那样工作。
我的问题是,当我快速点击时,这意味着当我等待并立即通知我的应用程序会挂起。
那我怎么能解决这个问题?
下面是我的代码:
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;
}
}
}
答案 0 :(得分:1)
run
不是volatile
,而是写在synchronized块之外。这意味着任务可能永远不会看到更新的值。Thread.sleep(10000)
您不会释放Task
上的锁定,这意味着可能发生以下情况:
playThread
方法将run
更改为false
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();
}