在 JavaFX 中每 3 秒循环一次线程



我目前正在开发一个股票市场应用程序,该应用程序每隔一段时间就会更改股票价格的值(对于此示例,让我们让股票每 3 秒更改一次值(。我考虑过做任务,但我找不到让任务连续运行的方法。有没有办法在主类中每 3 秒创建一个任务循环?(澄清一下,我希望将此循环任务添加到我的主方法的主体中,而不使用除主方法之外的外部类(

这是我到目前为止所拥有的:

Task<Void> change = new Task<Void>() {
@Override
protected Void call() throws Exception {
try {
Thread.sleep(3000);
} 
catch (InterruptedException e) {}
return null;
}
};
change.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {
}
});
new Thread(change).start(); 

注意:此代码是从此处引用的

不要用"连续"或"循环"来思考。相反,想想要完成的工作(查找新的股票价格(,以及您希望多久执行一次任务。

对于第一部分,即您的任务,定义一个Runnable(或Callable(。这意味着只需使用一种run方法来遵守接口的约定。

在 lambda 语法中:

Runnable runnable =
() -> { 
System.out.println( "Looking up fresh stock prices at " + Instant.now().toString() ) ; 
} 
;

接下来,研究现代Java中内置的Executors框架。请参阅甲骨文教程。此框架大大简化了在线程上调度工作的棘手工作。

具体来说,您要使用ScheduledExecutorService.此接口用于将任务安排为在特定时间运行一次(实际上,在特定延迟到期后运行一次(,重复运行任务。你当然想要后者。

Executors类获取实现。为了满足您的需求,我们只需要一个单线程。在其他情况下,您可能希望使用线程池。

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ;

您可以选择两种计划变体:scheduleAtFixedRate​scheduleWithFixedDelay​。研究它们以决定哪种最适合您的情况。无论哪种情况,都要知道您不能完全依赖调度。您的主机操作系统控制向 JVM 授予对 CPU 内核的访问权限,并且 JVM 可能会处理大量线程。因此,时间可能会偶尔延迟,尽管对于大多数业务应用程序来说,延迟应该是微不足道的。

ses.scheduleWithFixedDelay( runnable , 0L , 3L , TimeUnit.SECONDS ) ;

您可能希望捕获返回的ScheduledFuture对象以监视进度或完成情况。我们上面的代码行忽略了它。

重要说明请确保在不再需要或应用关闭时正常关闭执行程序服务。否则,您的线程可能会继续在后台运行,并在应用退出后幸存下来。

重要说明使用 try-catch 将任务包装在Runnable任务中。任何冒泡到 Runnable 对象级别的异常或错误都将导致执行程序服务以静默方式终止。不会再安排电话。搜索堆栈溢出以了解更多信息。

Runnable runnable =
( ) -> {
try
{
System.out.println( "Looking up fresh stock prices at " + Instant.now().toString() );
}
catch ( Exception e )
{
// … try to recover, if you want the scheduled executor service to continue scheduling this task.
// Or, at least, do logging/notifications to know when and why the scheduling of this task halted.
e.printStackTrace();
}
};

重要说明使用JavaFXSwingVaadin等 UI 框架时,切勿从后台线程访问/修改任何用户界面小部件。每个 UI 框架都将提供自己的机制,通过该机制,您可以安排要在UI 线程上执行的小部件更新工作。我不熟悉JavaFX,所以我不能更具体。

将所有这些放在此示例代码中。而且,对于那些不熟悉lambda语法的人,请使用匿名类作为我们的Runnable

package work.basil.example;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Bogus
{
public static void main ( String[] args )
{
Runnable runnable =
new Runnable()
{
@Override
public void run ( )
{
try
{
System.out.println( "Looking up fresh stock prices at " + Instant.now().toString() );
}
catch ( Exception e )
{
// … try to recover, if you want the scheduled executor service to continue scheduling this task.
// Or, at least, do logging/notifications to know when and why the scheduling of this task halted.
e.printStackTrace();
}
}
};
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleWithFixedDelay( runnable , 0L , 3L , TimeUnit.SECONDS );
try
{
Thread.sleep( TimeUnit.MINUTES.toMillis( 1 ) );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
ses.shutdown();  // IMPORTANT Always shutdown gracefully your executor service so the thread pool does not outlive your app.
}
System.out.println( "INFO - Completed run at: " + Instant.now() );
}
}

运行时。

在2020-02-15T06:35:35.987199Z查找新鲜股价

在2020-02-15T06:35:39.026132Z查找新鲜股价

在2020-02-15T06:35:42.030302Z查找新鲜股价

在2020-02-15T06:35:45.035176Z查找新鲜股票价格

在2020-02-15T06:36:30.097743Z查找新鲜股价

在2020-02-15T06:36:33.100713Z查找新鲜股票价格

信息 - 完成运行时间:2020-02-15T06:36:35.988752Z

如上所述,请注意任务之间的间隔不是正好三秒,而是非常接近。这个例子是在 Mac mini 上运行的,它有 6 个真正的内核,没有超线程,32 GB 内存,在 macOS Mojave 上,使用 Java 13。

最新更新