Java - 轮询超时的最佳方式

时间:2013-01-08 11:07:30

标签: java

我的代码如下:

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的情况下测试超时的最佳方法是什么?这是正确的方法吗?

2 个答案:

答案 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();
}