用于超时参数的java.util.concurrent.TimeUnit vs java.time.Duration

时间:2015-09-01 01:36:06

标签: java java-8

编写API时,我倾向于定义将 timeout 参数作为参数long timeout, TimeUnit unit的方法。这遵循许多具有相同要求的java.util.concurrent方法。

在Java 8中,我注意到Duration包中的新java.time类,并想知道我是否可以将新方法定义为具有Duration timeout参数。

我可以从中看到的优点是:

  • 用户编写常量更容易:

    private static final Duration ACQUIRE_TIMEOUT = Duration.ofMinutes(10);
    
    someResource.acquire(ACQUIRE_TIMEOUT);
    

    VS

    private static final long ACQUIRE_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(10);
    
    someResource.acquire(ACQUIRE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    

但这是一个可能的问题:

  • 用户如何指定无限时间?

    someResource.acquire(Long.MAX_VALUE, TimeUnit.MILLISECONDS); // No timeout
    

    VS

    someResource.acquire(Duration.ofSeconds(Long.MAX_VALUE)); // Is this how it's done?
    

    其中acquire(Duration)可以实现为:

    public boolean acquire(Duration timeout) {
        long millis;
        try { millis = timeout.toMillis(); }
        catch (ArithmeticException ignore) { millis = Long.MAX_VALUE; } // yuck!
    
        ...
    }
    

    绝对不是最漂亮的代码。

有更好的方法吗?是否有其他问题或原因我不应该在我提供的API中使用java.time.Duration作为超时参数?

3 个答案:

答案 0 :(得分:6)

您的代码

private static final long ACQUIRE_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(10);
someResource.acquire(ACQUIRE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);

抵消了在特定应用单元中与该单元一起提供值的预期用途。预期用途应为someResource.acquire(10, TimeUnit.MINUTES);

但是它显示了这种方法的问题,因为不可能定义一个带有值和TimeUnit的常量。所以Duration在这里有一点意义。

由于TimeUnit是为并发API创建并且在大多数情况下由后端代码使用的众所周知类型,因此我绝不会省略具有(long,TimeUnit)签名的方法,而是提供接受{的重载{1}}没错。

当谈到“无超时”问题时,大多数API都没有对Duration进行特殊处理,无论它是以秒还是毫秒提供。观察到的“无超时”行为是由于数量Long.MAX_VALUE(Long.MAX_VALUE, TimeUnit.SECONDS)都表示时间,今天的计算机都无法生存。如果人类持续那么久,我们会很高兴。使用(Long.MAX_VALUE, TimeUnit.MILLISECONDS)会表现出相同的行为。

顺便说一下,一些并发工具无条件地在内部将超时转换为纳秒级,这意味着最大等待时间仅限于300年“仅”,但我认为对于大多数仍然等于“实际上没有”的应用程序超时”。

换句话说,Long.MAX_VALUE-1Duration.ofSeconds(Long.MAX_VALUE)在运行时操作中用作超时时没有实际区别。

附录:我首先忽略了关于实际实施的问题。我建议遵循上述转换为纳秒的行为,而不是使用毫秒。我能想到的最好的事情是

Long.MAX_VALUE, TimeUnit.MILLISECONDS

有可能用毫秒来做类似的事情,但是,我认为将来毫秒内毫秒的不精确度更可能成为一个问题,而不是最大超时限制在292年以上。

答案 1 :(得分:2)

你不应该等待锁定的无限时间。锁定和解锁还有其他并发和线程间信令方法,你应该探索

java.time.Duration:来自Java 8新的日期和时间Api

java.util.concurrent.TimeUnit:来自Java并发包

如果我正在编写与并发或线程相关的代码,我会使用TimeUnit,但如果我正在编写操作Date的代码,那么我使用Java 8时我将使用java.time.Duration

答案 2 :(得分:0)

我定义了这些常量:

/** The maximum value of {@link Duration} */
public static final Duration MAX_DURATION = Duration.ofSeconds(Long.MAX_VALUE, 999_999_999);

/** The maximum value of a duration convertable to nanoseconds */
public static final Duration MAX_NANO_DURATION = Duration.ofNanos(Long.MAX_VALUE);

/** A pseudo value denoting an infinite duration */
// This value is lower than MAX_DURATION to be consistent with infiniteDuration(), see below
public static final Duration INFINITE_DURATION = Duration.ofSeconds(Long.MAX_VALUE);

这些方法:

/**
 * Converts the given duration to an accurate pair of seconds or nanoseconds and the corresponding {@link TimeUnit}. If the duration can't be expressed in
 * nanoseconds, the returned value will be the seconds with stripped nanoseconds.
 * @param duration duration to convert
 * @return pair of seconds / nanoseconds and time unit ({@link TimeUnit#SECONDS} / {@link TimeUnit#NANOSECONDS})
 */
public static Pair<Long, TimeUnit> convertDurationToTimeUnit(Duration duration) {
    return duration.compareTo(Durations.MAX_NANO_DURATION) > 0
            ? Pair.of(duration.getSeconds(), TimeUnit.SECONDS)
            : Pair.of(duration.toNanos(), TimeUnit.NANOSECONDS);

/**
 * Returns the infinite duration as a pair of the number of seconds or nanoseconds and the corresponding {@link TimeUnit}.
 * @return the infinite duration as pair of time value and {@link TimeUnit} ({@link Long#MAX_VALUE} and {@link TimeUnit#SECONDS}).
 */
public static Pair<Long, TimeUnit> infiniteDuration() {
    return convertDurationToTimeUnit(MAX_DURATION);
}

使用它:

public boolean await(Duration duration) throws InterruptedException {
    Pair<Long, TimeUnit> timeout = convertDurationToTimeUnit(duration);
    return signal.await(timeout.getLeft(), timeout.getRight());
}

...无限:

public boolean awaitInfinitely() throws InterruptedException {
    Pair<Long, TimeUnit> timeout = convertDurationToTimeUnit(INFINITE_DURATION);
    return signal.await(timeout.getLeft(), timeout.getRight());
}