@Override
    public void offer(long value) {
        long[] localValues = values;
        int length = localValues.length;
        int localReadIndex = readIndex;
        int localWriteIndex = writeIndex;
        if ((localWriteIndex - localReadIndex) == length) {
            // grow the array
            while (!LOCK_UPDATER.compareAndSet(this, 0, 1)) {
            }
            try {
                localReadIndex = readIndex;
                int newSize = length << 1;
                long[] newValues = new long[newSize];
                int rightValueCount = length - localReadIndex;
                System.arraycopy(localValues, localReadIndex, newValues, 0, rightValueCount);
                if (localReadIndex != 0) {
                    System.arraycopy(localValues, 0, newValues, rightValueCount, localReadIndex);
                }
                newValues[localWriteIndex & (newValues.length - 1)] = value;
                values = newValues;
                readIndex = 0;
            } finally {
                LOCK_UPDATER.set(this, 0);
            }
        } else {
            VALUES_HANDLE.setVolatile(localValues, localWriteIndex & (length - 1), value);
        }
        writeIndex++;
    }
The lock is used to ensure the resize operation and the drain operation won't happen
simultaneously.
turms-server-common/src/main/java/im/turms/server/common/infra/collection/SpscGrowableLongRingBuffer.java