I want to check for a condition in a guarded wait() loop with a user-specified total timeout, similar to how LinkedBlockingQueue.poll() works.
For example collection can be appended to by different threads, but only when the collection contains a value equating to myItem within timeout, should the loop terminate successfully. If the user-specified timeout elapses, it should throw.
This is my current best approach:
long startTime = System.currentTimeMillis();
synchronized (collection) {
while (!collection.contains(myItem)) {
long remaining = System.currentTimeMillis() - startTime - timeout;
if (remaining < 0)
throw new TimeoutException();
collection.wait(remaining);
}
}
The problem here is that System.currentTimeMillis() (or System.nanoTime()) is called inside a synchronized context. IntelliJ's warning states:
While not necessarily representing a problem, such calls cause an expensive context switch, and are best kept out of synchronized contexts, if possible.
I wonder how much impact this 'expensive context switch' will have in practice, with Oracle JVM 8?
This is one alternative I came up with, but I don't like this as the actual timeout becomes ⌊timeout/10⌋*10 + delta. and the error will probably be much worse than the context switch.
synchronized (collection) {
int loops = 0;
while (!collection.contains(myItem)) {
if(loops++ > timeout / 10)
throw new TimeoutException();
collection.wait(10);
}
}