Based on a lot of questions I received in various mailing lists related to the previous post and in order to make the issue simpler and clearer I decided to go back to a binary deliverable (code) that shows the problem, hope this helps!

This is my PreciousPool class, that handles Precious resources:

import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class PreciousPool { public static class Precious { private final int id; private Precious() { this.id = 100+(int)(Math.random()*900.0); } public String toString() { return "Precious n."+id; } } private final Lock lock; private final Condition ready; private final long timeoutInMillis; private final List preciousLended; private final List preciousAvailable; public PreciousPool(int size, long timeoutInSeconds) { this.lock = new ReentrantLock(); this.ready = lock.newCondition(); this.timeoutInMillis = 1000L*timeoutInSeconds; this.preciousLended = new ArrayList(); this.preciousAvailable = new ArrayList(); for (int i = 0; i < size; i++) { preciousAvailable.add(new Precious()); } } public Precious obtain() { lock.lock(); try { // if no precious are available we wait for the specified timeout (releasing the lock so that others can try) if (preciousAvailable.size() == 0) { try { ready.await(timeoutInMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Somebody interrupted me!", e); } } // if a precious is available we unload it and return to the caller, otherwise null if (preciousAvailable.size() > 0) { Precious value = preciousAvailable.remove(0); preciousLended.add(value); return value; } else { return null; } } finally { lock.unlock(); } } public void release(Precious value) { lock.lock(); try { if (!preciousLended.remove(value)) throw new RuntimeException("Element "+value+" was not lended!"); // if a precious is returned we put it back and signal to anybody waiting preciousAvailable.add(value); ready.signalAll(); } finally { lock.unlock(); } } public static void main(String args[]) { final int size = 3; final PreciousPool pool = new PreciousPool(size, 5); // let's exhaust the pool for (int i=0; i<size; i++) dump(pool.obtain()); // and as we are stubborn we continuosly ask for a new one while(true) { dump(pool.obtain()); } } private static void dump(Precious precious) { if (precious == null) log("I did not get my precious :("); else log("I did get my precious! "+precious); } private static void log(String message) { final String now = new SimpleDateFormat("HH:mm:ss:SSSS ").format(new Date()); System.out.println(now + message); } }

So, the main is a single thread (no need for multithreading here, let’s keep it simple), that first exhaust the whole pool and then keep asking, without success, for a resource. Stubborn guy, I say, but it happens. If you run this program everything works as expected: you are greeted by a three successful Precious and then an endless list of failures, that it continuously grow. All good 🙂

02:34:40:0061 I did get my precious! Precious n.156 02:34:40:0062 I did get my precious! Precious n.991 02:34:40:0062 I did get my precious! Precious n.953 02:34:45:0064 I did not get my precious! 02:34:50:0065 I did not get my precious! 02:34:55:0066 I did not get my precious! 02:35:00:0067 I did not get my precious! 02:35:05:0068 I did not get my precious! [...]

But guess what happens when, while the program is running, I change the date of my system back of one hour? Everything stops, it’s simple as that. No prints, nothing, zero, nada. Now, If it wasn’t so late, I would probably wait one hour in order to have my program restored to his normal process, but as a customer I won’t be terribly happy 🙂

See also

The full saga, all the articles I published on the matter: