间隔运行 Java 线程

Posted

技术标签:

【中文标题】间隔运行 Java 线程【英文标题】:Running a Java Thread in intervals 【发布时间】:2009-01-09 01:36:42 【问题描述】:

我有一个线程需要每 10 秒执行一次。此线程包含对另一台服务器上的数据库的多次调用 (12 - 15)。此外,它还访问大约 3 个文件。因此,会有相当多的 IO 和网络开销。

执行上述操作的最佳策略是什么?

一种方法是使用 sleep 方法和 while 循环,但这是一个糟糕的设计。

在这种情况下,类似于 Timer 的类会有所帮助吗?另外,创建多个线程(一个用于 IO,一个用于 JDBC)而不是让它们在一个线程中运行会更好吗?

【问题讨论】:

为什么睡眠设计不好?当然不是每 10 秒一次,而是每 10+n 秒一次。但是,如果其中一个通行证需要 12 秒才能完成,那么无论如何您都不能保证 10 秒。如果您只是想尽量减少服务器上的负载,那么无论是睡眠还是定时器都没什么区别。 我指的是睡眠和 while 循环,作为一个糟糕的设计。因为,决定何时以及如何终止线程可能不是很直观。 【参考方案1】:

我发现ScheduledExecutorService 是一个很好的方法。可以说它比Timer 稍微复杂一些,但在交换方面提供了更大的灵活性(例如,您可以选择使用单个线程或线程池;它需要的单位不仅仅是毫秒)。

ScheduledExecutorService executor =
    Executors.newSingleThreadScheduledExecutor();

Runnable periodicTask = new Runnable() 
    public void run() 
        // Invoke method(s) to do the work
        doPeriodicWork();
    
;

executor.scheduleAtFixedRate(periodicTask, 0, 10, TimeUnit.SECONDS);

【讨论】:

如果您不使用单线程执行程序,我可能倾向于将 doPeriodicWork() 调用包装在“同步 (this)”块中以确保安全。 那肯定会保护;将 doPeriodicWork 声明为 synchronized 将完成同样的事情,并且可能更简洁一些。话虽如此,doPeriodicWork 中可能有更小的关键部分,如果移动到线程池,可以单独保护它们。 @GregCase:如果您在executor 运行时更改periodicTask,您如何让executor 自行更新以在运行时使用最新的periodicTask @ThreaT:没有办法直接换出 Runnable 实例。您有 2 个选项:取消(使用 schedule 返回的 ScheduledFuture)并使用新的 Runnable 重新提交,或者将您的 Runnable 实例设置为具有状态,以便它委托给另一个对象实例,然后即时交换该对象实例。请注意,如果您这样做,您的 Runnable 可能无法像答案中的示例那样成为匿名内部类;您至少需要声明一个存储委托实例的字段并将引用保存在某个地方以便能够更新该字段。【参考方案2】:

一种选择是创建一个 ScheduledExecutorService,然后您可以将您的工作安排到该服务:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.scheduleWithFixedDelay(...);

如果您确实决定拥有多个线程,那么您可以创建一个具有更多线程的 ScheduledExecutorService(同样,通过 Executors 类)。

就线程数和每个线程中的内容而言,就性能而言,我想说这取决于:

对于您的特定应用程序,一个线程能否真正“工作”而另一个线程正在等待 I/O? 您的多个线程最终会“破坏同一个资源”(例如,从同一个 dsk 上不同位置的文件中读取)从而减慢彼此的速度,还是它们会同时访问不同的资源?

【讨论】:

【参考方案3】:

查看Timer 和TimerTask 类。它们正是您想要的。

您可以创建一个 TimerTask 实现,将您的线程对象放入构造函数中。

run 方法随后会调用线程的 run 方法。

// Perhaps something like this
Timer t = new Timer();
t.scheduleAtFixedRate(yourTimerTask, 0, 10 * 1000);
// Hopefully your task takes less than 12 seconds

【讨论】:

10 个字符只是一个建议! 我刚刚尝试输入“!”。我得到了可怕的“请输入至少 10 个字符”。当我单击 AddComment 时,在输入框下方。它实际上并没有进入评论。你是怎么做到的?? 如果你输入 !。你可以欺骗系统。它似乎将空格算作一个字符,然后在需要时删除多余的空格。 是的,你不能在开头或结尾放空格,它们必须在中间!谁写了这个废话? :-)

以上是关于间隔运行 Java 线程的主要内容,如果未能解决你的问题,请参考以下文章

Jmeter-线程组中线程的启动间隔

Python线程以精确的时间间隔执行

间隔在jmeter中运行特定的采样器

以指定的时间间隔定期运行异步方法

如何在python中创建一个在间隔函数调用上线程化的后台?

jmeter测试范例001——TCP测试