class BoundedBlockingObjectPool<T> extends AbstractObjectPool<T>
        implements BlockingObjectPool<T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(
        BoundedBlockingObjectPool.class);

    private final int size;
    private final LinkedBlockingDeque<T> objects;
    private final ObjectValidator<T> validator;
    private final ObjectFactory<T> objectFactory;
    private final ExecutorService executor = Executors.newCachedThreadPool(new OpenGrokThreadFactory("bounded"));
    private volatile boolean puttingLast;
    private volatile boolean shutdownCalled;

    public BoundedBlockingObjectPool(int size, ObjectValidator<T> validator,
        ObjectFactory<T> objectFactory) {

        this.objectFactory = objectFactory;
        this.size = size;
        this.validator = validator;

        objects = new LinkedBlockingDeque<>(size);
        initializeObjects();
    }

    @Override
    public T get(long timeOut, TimeUnit unit) {
        if (!shutdownCalled) {
            T ret = null;
            try {
                ret = objects.pollFirst(timeOut, unit);
                /*
                 * When the queue first empties, switch to a strategy of putting
                 * returned objects last instead of first.
                 */
                if (!puttingLast && objects.isEmpty()) {
                    puttingLast = true;
                }
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
            }
            return ret;
        }
        throw new IllegalStateException("Object pool is already shutdown");
    }

    @Override
    public T get() {
        if (!shutdownCalled) {
            T ret = null;
            try {
                ret = objects.takeFirst();
                /*
                 * When the queue first empties, switch to a strategy of putting
                 * returned objects last instead of first.
                 */
                if (!puttingLast && objects.isEmpty()) {
                    puttingLast = true;
                }
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
            }
            return ret;
        }
        throw new IllegalStateException("Object pool is already shutdown");
    }

    @Override
    public void shutdown() {
        shutdownCalled = true;
        executor.shutdownNow();
        clearResources();
    }

    private void clearResources() {
        for (T t : objects) {
            validator.invalidate(t);
        }
    }

    @Override
    protected void returnToPool(T t) {
        if (validator.isValid(t)) {
            executor.submit(new ObjectReturner<>(objects, t, puttingLast));
        }
    }

    /*
     * Creates a new instance, and returns that instead to the pool.
     */
    @Override
    protected void handleInvalidReturn(T t) {<FILL_FUNCTION_BODY>}

    @Override
    protected boolean isValid(T t) {
        return validator.isValid(t);
    }

    private void initializeObjects() {
        for (int i = 0; i < size; i++) {
            objects.add(objectFactory.createNew());
        }
    }

    private static class ObjectReturner<E> implements Callable<Void> {
        private final LinkedBlockingDeque<E> queue;
        private final E e;
        private final boolean puttingLast;

        ObjectReturner(LinkedBlockingDeque<E> queue, E e, boolean puttingLast) {
            this.queue = queue;
            this.e = e;
            this.puttingLast = puttingLast;
        }

        @Override
        public Void call() {
            while (true) {
                try {
                    if (puttingLast) {
                        queue.putLast(e);
                    } else {
                        queue.putFirst(e);
                    }
                    break;
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }

            return null;
        }
    }
}

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.log(Level.FINE, "createNew() to handle invalid {0}",
                t.getClass());
        }

        t = objectFactory.createNew();
        executor.submit(new ObjectReturner<>(objects, t, puttingLast));
    
<methods>public non-sealed void <init>() ,public final void release(T) <variables>