java让线程睡眠_java – 如何在线程上实现保证的睡眠时间

根据评论,主要目标不是在这个精确的时间间隔内同时执行多个任务.相反,目标是尽可能精确地以此间隔执行单个任务.

不幸的是,在这个意义上,ScheduledExecutorService和任何涉及Thread#sleep或LockSupport#parkNanos的手动构造都不是很精确.正如其他答案中所指出的:可能总会有一些影响因素超出您的控制范围 – 即JVM实施,垃圾收集,JIT运行等细节.

然而,在这里实现高精度的相对简单的方法是忙着等待. (这已在现已删除的答案中提及).但当然,这有几点需要注意.最重要的是,它将刻录一个CPU的处理资源. (在单CPU系统上,这可能特别糟糕).

但是为了表明它可能比其他等待方法更精确,这里是ScheduledExecutorService方法和忙碌等待的简单比较:

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

public class PreciseSchedulingTest

{

public static void main(String[] args)

{

long periodMs = 50;

PreciseSchedulingA a = new PreciseSchedulingA();

a.setup(periodMs);

PreciseSchedulingB b = new PreciseSchedulingB();

b.setup(periodMs);

}

}

class CallTracker implements Runnable

{

String name;

long expectedPeriodMs;

long baseTimeNs;

long callTimesNs[];

int numCalls;

int currentCall;

CallTracker(String name, long expectedPeriodMs)

{

this.name = name;

this.expectedPeriodMs = expectedPeriodMs;

this.baseTimeNs = System.nanoTime();

this.numCalls = 50;

this.callTimesNs = new long[numCalls];

}

@Override

public void run()

{

callTimesNs[currentCall] = System.nanoTime();

currentCall++;

if (currentCall == numCalls)

{

currentCall = 0;

double maxErrorMs = 0;

for (int i = 1; i < numCalls; i++)

{

long ns = callTimesNs[i] - callTimesNs[i - 1];

double ms = ns * 1e-6;

double errorMs = ms - expectedPeriodMs;

if (Math.abs(errorMs) > Math.abs(maxErrorMs))

{

maxErrorMs = errorMs;

}

//System.out.println(errorMs);

}

System.out.println(name + ", maxErrorMs : " + maxErrorMs);

}

}

}

class PreciseSchedulingA

{

public void setup(long periodMs)

{

CallTracker callTracker = new CallTracker("A", periodMs);

ScheduledExecutorService se = Executors.newScheduledThreadPool(20);

se.scheduleAtFixedRate(callTracker, periodMs,

periodMs, TimeUnit.MILLISECONDS);

}

}

class PreciseSchedulingB

{

public void setup(long periodMs)

{

CallTracker callTracker = new CallTracker("B", periodMs);

Thread thread = new Thread(new Runnable()

{

@Override

public void run()

{

while (true)

{

long periodNs = periodMs * 1000 * 1000;

long endNs = System.nanoTime() + periodNs;

while (System.nanoTime() < endNs)

{

// Busy waiting...

}

callTracker.run();

}

}

});

thread.setDaemon(true);

thread.start();

}

}

同样,这应该是一粒盐,但MyMachine®上的结果如下:

A, maxErrorMs : 1.7585339999999974

B, maxErrorMs : 0.06753599999999693

A, maxErrorMs : 1.7669149999999973

B, maxErrorMs : 0.007193999999998368

A, maxErrorMs : 1.7775299999999987

B, maxErrorMs : 0.012780999999996823

显示等待时间的错误在几微秒的范围内.

为了在实践中应用这种方法,需要更复杂的基础设施.例如.为了弥补过高的等待时间而需要的簿记. (我认为它们不能太低).而且,所有这些仍然不能保证精确定时执行.但至少可以考虑它.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值