编写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
作为超时参数?
答案 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-1
和Duration.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());
}