Use a ReentrantReadWriteLock for improved concurrency

The BoundedBlockingQueue currently uses a single lock for both read and write operations. We can leverage a ReentrantReadWriteLock to improve overall concurrency.