class ThreadLocalBufferManager
{
    /**
     * A lock to make sure releaseBuffers is only executed by one thread at a time
     * since it iterates over and modifies the allSoftBufRecyclers.
     */
    private final ReentrantLock RELEASE_LOCK = new ReentrantLock();

    /**
     * A set of all SoftReferences to all BufferRecyclers to be able to release them on shutdown.
     * 'All' means the ones created by this class, in this classloader.
     * There may be more from other classloaders.
     * We use a HashSet to have quick O(1) add and remove operations.
     *<p>
     * NOTE: assumption is that {@link SoftReference} has its {@code equals()} and
     * {@code hashCode()} implementations defined so that they use object identity, so
     * we do not need to use something like {@link IdentityHashMap}
     */
    private final Map<SoftReference<BufferRecycler>,Boolean> _trackedRecyclers
        = new ConcurrentHashMap<>();

    /**
     * Queue where gc will put just-cleared SoftReferences, previously referencing BufferRecyclers.
     * We use it to remove the cleared softRefs from the above set.
     */
    private final ReferenceQueue<BufferRecycler> _refQueue = new ReferenceQueue<>();

    /*
    /**********************************************************
    /* Public API
    /**********************************************************
     */

    /**
     * Returns the lazily initialized singleton instance
     */
    public static ThreadLocalBufferManager instance() {
        return ThreadLocalBufferManagerHolder.manager;
    }

    /**
     * Releases the buffers retained in ThreadLocals. To be called for instance on shutdown event of applications which make use of
     * an environment like an appserver which stays alive and uses a thread pool that causes ThreadLocals created by the
     * application to survive much longer than the application itself.
     * It will clear all bufRecyclers from the SoftRefs and release all SoftRefs itself from our set.
     */
    public int releaseBuffers() {<FILL_FUNCTION_BODY>}

    public SoftReference<BufferRecycler> wrapAndTrack(BufferRecycler br) {
        SoftReference<BufferRecycler> newRef;
        newRef = new SoftReference<>(br, _refQueue);
        // also retain softRef to br in a set to be able to release it on shutdown
        _trackedRecyclers.put(newRef, true);
        // gc may have cleared one or more SoftRefs, clean them up to avoid a memleak
        removeSoftRefsClearedByGc();
        return newRef;
    }

    /*
    /**********************************************************
    /* Internal methods
    /**********************************************************
     */

    /**
     * Remove cleared (inactive) SoftRefs from our set. Gc may have cleared one or more,
     * and made them inactive.
     */
    private void removeSoftRefsClearedByGc() {
        SoftReference<?> clearedSoftRef;
        while ((clearedSoftRef = (SoftReference<?>) _refQueue.poll()) != null) {
            // uses reference-equality, quick, and O(1) removal by HashSet
            _trackedRecyclers.remove(clearedSoftRef);
        }
    }

    /**
     * ThreadLocalBufferManagerHolder uses the thread-safe initialize-on-demand, holder class idiom that implicitly
     * incorporates lazy initialization by declaring a static variable within a static Holder inner class
     */
    private static final class ThreadLocalBufferManagerHolder {
        static final ThreadLocalBufferManager manager = new ThreadLocalBufferManager();
    }
}

        int count = 0;
        RELEASE_LOCK.lock();
        try {
            // does this need to be in sync block too? Looping over Map definitely has to but...
            removeSoftRefsClearedByGc(); // make sure the refQueue is empty
            for (SoftReference<BufferRecycler> ref : _trackedRecyclers.keySet()) {
                ref.clear(); // possibly already cleared by gc, nothing happens in that case
                ++count;
            }
            _trackedRecyclers.clear(); //release cleared SoftRefs
        } finally {
            RELEASE_LOCK.unlock();
        }
        return count;
    
<no_super_class>