Lock sharedLock = new ReentrantLock();
Condition condition = lock.newCondition();
main thread:
sharedLock.lock();
childThread.start();
condition.await(5, TimeUnit.SECONDS);
sharedLock.unlock();
child thread:
sharedLock.lock();
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
condition.signal();
sharedLock.unlock();
Suppose child thread send a network request and wait for response, I want main thread wait at most 5 seconds, if timeout, retry the request. but when the await() timeout, it cannot acquire lock because child thread still hold it, so it still wait the lock until child thread release it, which takes 10 seconds.
How can I achieve my requirement that main thread wait child thread's signal, but have a bounded timeout?
This is not how your are supposed to do it, you are supposed to:
ExecutorService (thread pool) for that you should check the methods of the class Executors to choose the best one in your case but Executors.newFixedThreadPool is a good startFutureTask to the thread poolget with a timeoutTimeoutException Here is how it could be done:
// Total tries
int tries = 3;
// Current total of tries
int tryCount = 1;
do {
// My fake task to execute asynchronously
FutureTask<Void> task = new FutureTask<>(
() -> {
Thread.sleep(2000);
return null;
}
);
// Submit the task to the thread pool
executor.submit(task);
try {
// Wait for a result during at most 1 second
task.get(1, TimeUnit.SECONDS);
// I could get the result so I break the loop
break;
} catch (TimeoutException e) {
// The timeout has been reached
if (tryCount++ == tries) {
// Already tried the max allowed so we throw an exception
throw new RuntimeException(
String.format("Could execute the task after %d tries", tries),
e
);
}
}
} while (true);
How can I achieve my requirement that main thread wait child thread's signal, but have a bounded timeout?
Here is how you can achieve your requirements:
Main Thread:
lock.lock();
try {
childThread.start();
condition.await(5, TimeUnit.SECONDS);
} finally {
sharedLock.lock();
}
The child thread:
try {
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
} finally {
// Here we notify the main thread that the task is complete whatever
// the task failed or not
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
As you can see to work, the task must not be performed within the critical section, we only acquire the lock to notify the main thread nothing more. Otherwise if you execute the task within the critical section after the timeout the main thread will still need to acquire the lock once again and since the lock is actually owned by the child thread, it will need to wait anyway until the end of the task which makes the timeout totally useless.
NB: I renamed sharedLock to lock as a ReentrantLock is an exclusive lock not as shared lock, if you need a shared lock check the class Semaphore to define the total amount of permits.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With