As has been pointed out, a bounded BlockingQueue alone would be sufficient. For example, the following code will do what you want:
import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public final class Pool<T> {
private final BlockingQueue<T> objects;
public Pool(Collection<? extends T> objects) {
this.objects = new ArrayBlockingQueue<T>(objects.size(), false, objects);
}
public T borrow() throws InterruptedException {
return this.objects.take();
}
public void giveBack(T object) throws InterruptedException {
this.objects.put(object);
}
}
Also, you might want to consider supporting a timed version of borrow() using BlockingQueue.poll().
If you didn't have a bounded blocking queue data structure, then you can impose a semaphore on top of any data structure to create a thread safe and bound behavior.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…