如何在可以更改的时间间隔后重复运行一些代码?

时间:2017-03-11 06:20:17

标签: java javafx

我在JavaFX中使用一个线程在一个间隔(最初1s)之后重复我的代码,但是我希望能够根据用户选择将线程使用的间隔更改为500ms或333ms(我有菜单栏中的按钮可针对每个选项进行更改)。如果用户点击其中一个按钮并使用新值再次启动它,我确实尝试过shutDown()之类的东西,但是没有用。有什么想法吗?

这是我的代码的相关部分:

ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(() -> {
        //refresh users, line and "guiche"
        updateFila(usuarios, guiches, fila);
        updateGuiche(guiches, fila, graphicsContext);
        turno++;
        //ends the code after the end of the line
        if (done) {
            exec.shutdown();
        }
}, 0, 1000, TimeUnit.MILLISECONDS); //This is interval that I need to change after user choice


我知道我现在正在执行 scheduleAtFixedRate(),但这只是为了看看逻辑是否正常。

此外,我需要根据用户点击暂停,恢复和重置线程。

2 个答案:

答案 0 :(得分:1)

您可以使用Timeline每秒执行一次事件处理程序,并将动画运行的速率设置为每秒更新应发生的次数,即2或3 ......

在下面的示例中,我使用5而不是3来获得更易识别的效果:

@Override
public void start(Stage primaryStage) {
    Line line = new Line(25, 125, 125, 125);
    Rotate rotate = new Rotate(0, 125, 125);
    line.getTransforms().add(rotate);

    ToggleButton btn = new ToggleButton();
    btn.textProperty().bind(Bindings.when(btn.selectedProperty()).then("5 Hz").otherwise("2 Hz"));
    StackPane.setAlignment(btn, Pos.BOTTOM_LEFT);

    // rotate by one 60th of a full rotation each time
    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), evt -> rotate.setAngle((rotate.getAngle() + (360d / 60d)) % 360)));
    timeline.setCycleCount(Animation.INDEFINITE);

    // rate depends on button state
    timeline.rateProperty().bind(Bindings.when(btn.selectedProperty()).then(5d).otherwise(2d));

    Pane linePane = new Pane(line);
    linePane.setMinSize(250, 250);
    linePane.setMaxSize(250, 250);
    StackPane root = new StackPane();
    root.getChildren().addAll(linePane, btn);

    Scene scene = new Scene(root, 300, 300);

    primaryStage.setScene(scene);
    timeline.play();

    primaryStage.show();
}

绑定只是设置更新频率的一个示例。您当然可以使用不同的方法来分配此值,例如

ComboBox<Duration> combo = new ComboBox<>();
Duration initial = Duration.seconds(1);
combo.getItems().addAll(initial, Duration.seconds(1/3d), Duration.seconds(1/2d));
combo.setValue(initial);
combo.valueProperty().addListener((observable, oldValue, newValue) -> timeline.setRate(1/newValue.toSeconds()));

答案 1 :(得分:0)

如果只使用单线程,则可以基于经典线程创建自己的实现。

public class Worker extends Thread {

private static final Logger logger = Logger.getLogger(Worker.class);

private volatile int delayInSec = 1;

private CountDownLatch latch;

private final int STARTED = 0;
private final int STOPPED = 1;
private volatile int state = STOPPED;

public Worker(){}


@Override
public void run() {

    logger.debug("enter to execution method");

    while (!isInterrupted()) {

        // stop if needed (it's additional feature)
        if (state == STOPPED) {
            logger.debug("stopped and locked");
            try {
                latch = new CountDownLatch(1);
                latch.await();
            } catch (InterruptedException e) {
                logger.warning("got interruption while waiting for action ", e);
                break;
            }
            logger.debug("awake");
        }

        // do your stuff here

        try {
            // then delay
            logger.debug("go to sleep for %s sec.",delayInSec);
            latch = new CountDownLatch(1);
            latch.await(delayInSec, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            logger.warning("got interruption while waiting for action ", e);
            break;
        }


    }

    logger.debug("exit from execution method");

}


public void startJob(){
    state = STARTED;
    logger.debug("started");
    if (latch!=null)
       latch.countDown();
}

public void stopJob(){  
    state =  STOPPED;
    logger.debug("stopped");
}


public void shutdown(){
    logger.debug("shutdown");
    interrupt();
}

public void changeDelay(int delayInSec) {
    logger.debug("set new delay %s", delayInSec);
    this.delayInSec = delayInSec;       
}


}