java - Precision alternative to Thread.sleep()
问题描述
I need a way to delay a thread for a precise number of milliseconds (a music score playing application). I know that the precision of Thread.sleep()
is not very good, so I decided to instead use ScheduledExecutorService
. The way I do this is below:
... //some code
int duration = 100; //delay for 100ms
CountDownLatch l = new CountDownLatch(1);
Executors.newScheduledThreadPool(1).schedule(l::countDown, duration, TimeUnit.MILLISECONDS);
l.await();
... //continue execution
Is this a good approach? I am mostly worried about the CountDownLatch, and any delay (if any) it may add.
Thanks.
解决方案
因此,由于一些问题,您的解决方案并不好。您正在失去使用计划执行程序服务获得的优势,通过使用await
await 将使当前线程进入睡眠状态,然后操作系统将需要在它启动之前再次安排它。
我使用三种不同的技术做了一个例子。旋转等待,使用 thread.sleep 并使用您计划的执行程序想法。旋转等待是最准确的,为 7002 毫秒,而其他两个解决方案在完成时超过 8300 毫秒。
import java.util.concurrent.*;
public class DwellTimes{
static public void spinWait(long ms){
long end = System.nanoTime() + ms*1000000;
long current = System.nanoTime();
while( current < end){
current = System.nanoTime();
}
}
static public void sleepWait(long ms){
try{
Thread.sleep(ms);
} catch(Exception e){
throw new RuntimeException(e);
}
}
static ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
static public void scheduleWait(long ms){
try{
CountDownLatch l = new CountDownLatch(1);
ses.schedule(l::countDown, ms, TimeUnit.MILLISECONDS);
l.await();
} catch(Exception e){
throw new RuntimeException(e);
}
}
public static void main(String[] args){
long start = System.currentTimeMillis();
for(int i = 0; i<1000; i++){
scheduleWait(7);
}
long end = System.currentTimeMillis() - start;
System.out.println( end + "ms elapsed");
}
}
对于睡眠/等待风格的流程,旋转等待将是最准确的,因为它不会释放线程。它只会继续发热。
您计划的执行程序示例的问题在于您实际上并没有使用计划。你想安排你的任务。
public static void scheduleWork(){
CountDownLatch latch = new CountDownLatch(1000);
ses.scheduleAtFixedRate(latch::countDown, 7, 7, TimeUnit.MILLISECONDS);
try{
latch.await();
} catch(Exception e){
throw new RuntimeException(e);
}
}
最后一个示例可能是管理一致时序的最佳方式,因为您不会继续累积错误。例如,如果您的操作需要几毫秒,那么除非这几毫秒超过 period ,否则下一个操作不会延迟。
推荐阅读
- firebase - 在集合中创建随机文档时,有没有办法对集合进行排序?
- kubernetes - 对正在运行的 Kubernetes pod 进行脚本编辑
- html - 具有移动背景的 css 剪辑文本
- html - 当一张卡片获得更多内容时,w3-cards 不会调整高度
- python - 将图像转换为 TFRecords 后如何提取图像名称?
- javascript - Nodejs Scraper 没有移动到下一页
- sql - SQL 函数通过引用获取列
- javascript - 为什么我可以调用外部文件,但不能调用内部文件?
- java - XPath 返回一个元素但不返回另一个?
- javascript - 等效于使用 javascript 更改页面内容后的 readystatechange