我的代码如下:
while(isResponseArrived)
Thread.yield();
但我真正喜欢的是这样的事情:
long startTime = System.currentTimeInMilliseconds();
while(isResponseArrived)
{
if(isTimeoutReached(startTime))
throw new TimeOutExcepton();
Thread.yield();
}
我还不确定是否会抛出异常(这对于这个问题并不重要),但我想知道的是如何使其尽可能高效,所以我不会匆匆离开处理器。换句话说,如何使isTimeoutReached(long startTime)尽可能地表现友好。
我测试过:
for(int x=0; x<99999999; x++)
System.nanoTime();
与
for(int x=0; x<99999999; x++)
System.currentTimeInMilliseconds();
差异很小,完成时间不到10%
我也看看使用Thread.sleep(),但我真的希望如果有更新并且处理器正在等待,则尽快通知用户。 Thread.yield()没有得到处理器搅拌,它只是一个NOP,给其他任何处理器优先级,直到它好转。
无论如何,在没有限制CPU的情况下测试超时的最佳方法是什么?这是正确的方法吗?
答案 0 :(得分:2)
根据我的经验,对仲裁进行仲裁选择,例如不是时间关键。如果我选择1000毫秒的超时并且需要1001毫秒而不是影响应该是微不足道的。为了实现超时,我建议尽可能简化实现。
您可以使用ScheduledExecutorService实现超时,例如
final ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
public void addTimeoutForTask(final Future future, int timeOutMS) {
ses.schedule(new Runnable() {
@Override
public void run() {
future.cancel(true);
}
}, timeOutMS, TimeUnit.MILLISECONDS);
}
如果您正在执行某些非阻止操作,并且您希望此操作超时,则可以执行此操作。
interface TimedPoller {
public void poll();
/**
* @return is it now closed.
*/
public boolean checkTimeout(long nowNS);
}
private final Set<TimedPoller> timedPollers = new LinkedHashSet<>();
private volatile TimedPoller[] timedPollersArray = {};
public void add(TimedPoller timedPoller) {
synchronized (timedPollers) {
long nowNS = System.nanoTime();
if (!timedPoller.checkTimeout(nowNS) && timedPollers.add(timedPoller))
timedPollersArray = timedPollers.toArray(new TimedPoller[timedPollers.size());
}
}
public void remove(TimedPoller timedPoller) {
synchronized (timedPollers) {
if (timedPollers.remove(timedPoller))
timedPollersArray = timedPollers.toArray(new TimedPoller[timedPollers.size());
}
}
private volatile boolean running = true;
public void run() {
while (running) {
// check the timeout for every 1000 polls.
for (int i = 0; i < 1000; i += timedPollersArray.length) {
TimedPoller[] pollers = timedPollersArray;
for (TimedPoller poller : pollers) {
poller.poll();
}
}
long nowNS = System.nanoTime();
TimedPoller[] pollers = timedPollersArray;
for (TimedPoller poller : pollers) {
if (poller.checkTimeout(nowNS))
remove(poller);
}
}
}
要么放弃CPU,要么放弃CPU。如果放弃CPU,其他线程可以运行,但在再次运行之前会有延迟。或者你不放弃改善响应时间的CPU,但另一个线程无法运行。
看来你希望能够让其他东西运行,而不需要放弃CPU。这不是微不足道的,但如果做得正确可以给你两个好处(如果不能有效地完成两个,那么可以给你带来一些好处)
如果您有许多小任务,例如,您可以执行自己的线程逻辑。假设您想要调查十件事,您只能使用一个CPU。
答案 1 :(得分:2)
我认为使用wait / notify
会更有效率boolean arrived;
public synchronized void waitForResponse(long timeout) throws InterruptedException, TimeoutException {
long t0 = System.currentTimeMillis() + timeout;
while (!arrived) {
long delay = System.currentTimeMillis() - t0;
if (delay < 0) {
throw new TimeoutException();
}
wait(delay);
}
}
public synchronized void responseArrived() {
arrived = true;
notifyAll();
}