简体   繁体   中英

Creating an Atomic RingBuffer in Java

I was thinking of how I would go about implementing a thread-safe RingBuffer in Java and Android (as for some reason there is none, even after all these years, not even a circular queue. So, no (Circular/Ring)ByteBuffer, nor (Circular/Ring)(Buffer/Queue).

Even majority of the RingBuffer implementations that are third party are said to be not thread safe, which makes me think it really isn't as simple as I think it is going to be. What I was thinking about was doing something like this:

  • Have an Object (say RingBufferPosition) that encapsulates both the Head and Tail position.
  • Have the RingBuffer maintain an AtomicReference to the RingBufferPosition
  • When a thread adds something, it will create a temporary (unfortunately, I don't know enough of Java to determine this, but "Stack-allocated") object, which will be recycled over and over, updating it with the new updated head and tail, until it can CAS successfully.
  • When a thread removes something, it will do similar to adding something.
  • Everything is accessed in an array allocated to the max length, hence, the head and tail can access/update the current element in O(1) time.

Would this work, and better yet, would it yield any benefits over simply synchronizing access to the collection?

A small code sample/pseudocode (has not been run yet, and I do not even know how to remotely test an atomic data structure, I plan on using it for buffering/streaming media but I haven't gotten that far yet as I need to create this first) can be found here . I have comments/documentation that details my concerns there.

Lastly, to address a possible "Why" question, as in "Why do you need such performance", I'll be truthful. I have always found data structures, especially atomic/lock-free data structures very interesting, and I found this as a very good exercise to learn, plus I always wanted to create a Ring Buffer. I could have just "synchronized" everything, however I do also value performance.

Multiple reader/multiple writer ring buffers are tricky.

Your way doesn't work, because you can't update that start/end position AND the array contents atomically. Consider adding to the buffer: If you update the end position first, then there is a moment before you update the array when the buffer contains an invalid item. If you update the array first, then there's nothing to stop simultaneous additions from stomping on the same array element.

There are lots of ways to deal with these problems, but the various ways have different trade-offs, and you have better options available if you can get rid of the multiple reader or multiple writer requirement.

If I had to guess at why we don't have a concurrent ring buffer in the standard library, I'd say it's because there is no one best way to implement it that is going to be good for most scenarios. The data structure used for ConcurrentLinkedQueue, in contrast, is simple and elegant and an obvious choice when a concurrent linked list is required.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM