/** * Visible to unit tests. * * @see #get(Resource) */ @SuppressWarnings("unchecked") synchronized <T> T getInternal(Resource<T> resource) { Instance instance = instances.get(resource); if (instance == null) { instance = new Instance(resource.create()); instances.put(resource, instance); } if (instance.destroyTask != null) { instance.destroyTask.cancel(false); instance.destroyTask = null; } instance.refcount++; return (T) instance.payload; }
/** Visible to unit tests. */ synchronized <T> T releaseInternal(final Resource<T> resource, final T instance) { final Instance cached = instances.get(resource); if (cached == null) { throw new IllegalArgumentException("No cached instance found for " + resource); } Preconditions.checkArgument(instance == cached.payload, "Releasing the wrong instance"); Preconditions.checkState(cached.refcount > 0, "Refcount has already reached zero"); cached.refcount--; if (cached.refcount == 0) { Preconditions.checkState(cached.destroyTask == null, "Destroy task already scheduled"); // Schedule a delayed task to destroy the resource. if (destroyer == null) { destroyer = destroyerFactory.createScheduledExecutor(); } cached.destroyTask = destroyer.schedule( new LogExceptionRunnable( new Runnable() { @Override public void run() { synchronized (SharedResourceHolder.this) { // Refcount may have gone up since the task was scheduled. Re-check it. if (cached.refcount == 0) { resource.close(instance); instances.remove(resource); if (instances.isEmpty()) { destroyer.shutdown(); destroyer = null; } } } } }), DESTROY_DELAY_SECONDS, TimeUnit.SECONDS); } // Always returning null return null; }