private synchronized int read(Reader reader, ByteBuf dst, long position, int length) throws IOException {
        if (CAPACITY_NOT_SET == channel.capacity()) {
            // If we don't know the capacity now, we can't cache.
            return reader.read(dst, position, length);
        }

        long start = position;
        length = Math.min(length, dst.writableBytes());
        long end = position + length;

        ByteBuf cache = getCache();
        if (length > cache.capacity()) {
            // If the length is larger than the cache capacity, we can't cache.
            return reader.read(dst, position, length);
        }

        boolean fallWithinCache = cachePosition >= 0 && cachePosition <= start && end <= cachePosition + cache.readableBytes();
        if (!fallWithinCache) {
            cache.clear();
            cachePosition = start;
            // Make sure the cache is not larger than the channel capacity.
            int cacheLength = (int) Math.min(cache.writableBytes(), channel.capacity() - cachePosition);
            reader.read(cache, cachePosition, cacheLength);
        }

        // Now the cache is ready.
        int relativePosition = (int) (start - cachePosition);
        dst.writeBytes(cache, relativePosition, length);
        return length;
    }
As we use a common cache for all threads, we need to synchronize the read.
s3stream/src/main/java/com/automq/stream/s3/wal/util/WALCachedChannel.java