9

Basically I need a data structure to store the temporary chatting messages on the server side. It should be:

  • bounded: because I don't need store too many messages, the client will send request to get the new messages every second. I think the bound size should be the max. mount of concurrent requests in one second. When the buffer is full, the old messages will be removed.

  • suitable for high concurrent access: I don't want to use the data structure like Collections.synchronizedXXXX, because during the iteration, if other thread changes the data structure, e.g. adds a message, it will throw an Exception, so I have to lock the whole data structure, actually I don't really care if the client request can get the most last inserted message, because they will send a new request after one second, on the other side the write operation should be never delayed. The classes under the package java.util.concurrency seems the solution, but...

  • non-blocking: LinkedBlockingQueue, ArrayBlockingQueue they could be bounded and won't throw exception during iteration, but they are all blocking queue. When the queue is full, I want to add the new element to the tails and remove the old element from head instead of blocking there and wait for someone to remove the header.

So my question is there any good implementation from 3rd library? For example Google Guava? Or maybe you have better idea about storing the temporary chatting messages on server?

thank you very much!

cn1h
  • 1,188
  • 4
  • 16
  • 24
  • 3
    You could try a synchronized version of Apache Commons [CircularFifoBuffer](http://commons.apache.org/collections/apidocs/org/apache/commons/collections/buffer/CircularFifoBuffer.html). – Perception Apr 12 '12 at 20:07
  • thank you for your reply, actually the CircularFifoBuffer is exactly what i need. but it's not synchronized out of box, as its document suggests, i need: BufferUtils.synchronizedBuffer(new CircularFifoBuffer()); But I checked the source code of BufferUtils, it just add synchronized keyword to every public functions, just like the JRE Collections.synchronizedXXXX, the performance issues in this case are same. – cn1h Apr 13 '12 at 11:01
  • anyway i don't think the capacity of the buffer should be very large. so if I lock the whole data structure during reading, it should also not a big problem. i think your reply is the right answer, but i don't know how to accept it. – cn1h Apr 13 '12 at 11:11
  • Great that it can work for you. I created an answer from my original comment that you can accept. – Perception Apr 13 '12 at 11:21
  • Do you need multi-consumer, multi-producer or you have relaxed requirements, implementing concurrent ring buffer is not hard but you have to clear your needs. For instance having a single consumer (most naturally) makes quite a difference to multi-consumer scenario. – bestsss Jun 25 '12 at 07:57

5 Answers5

5

You can use LinkedBlockingQueue with the non-blocking methods offer (or add) and poll to access it. You can create it with a fixed capacity to make it bounded.

LinkedBlockingQueue<String> myStrings = new LinkedBlockingQueue<String>(100);
myStrings.offer("Hi!"); // returns false if limit is reached
myStrings.add("Hi, again!"); // throws exception if limit is reached
String s = myStrings.poll(); // returns null if queue is empty
Frederic Leitenberger
  • 1,949
  • 24
  • 32
4

You could utilize the Apache Commons CircularFifoBuffer. It meets your first and last criteria. To support concurrency, you can wrap the base buffer in it's synchronized version like so:

Buffer fifo = BufferUtils.synchronizedBuffer(new CircularFifoBuffer());

Good luck on the project.

Y.H.
  • 2,687
  • 1
  • 29
  • 38
Perception
  • 79,279
  • 19
  • 185
  • 195
3

Did you take a look at ConcurrentLinkedQueue? The page says

This implementation employs an efficient "wait-free" algorithm...

Wait-freedom is one of the strongest guarantee you can obtain....

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
  • 2
    ConcurrentLinkedQueue is not bounded. However it could be wrapped/subclassed to add the size behavior. – Colin D Apr 12 '12 at 20:27
  • 1
    I read again and you are right. unbounded wait-free? didn't knew such thing existed. They should correct the doc because it doesn't make sense – UmNyobe Apr 12 '12 at 20:43
  • disregard my earlier comment .I was mistaken bounded in the size of the queue with bounded in time of operations. – UmNyobe Apr 12 '12 at 22:02
  • 2
    @ColinD, you cant add size in atomic way, you can do it w/ LIFO structure but not FIFO. – bestsss Jun 25 '12 at 07:58
  • CLQ is lock-free NOT wait-free, it's quite a difference. – bestsss Jun 25 '12 at 07:59
1

You can add non-blocking behaviour to an ArrayBlockingQueue by surrounding it with a conditional offer() statement, where failure of the queue to accept the offer results in the head being dropped and the offer being re-made:

    public class LearnToQueue {


    public static void main(String[] args){
        Queue<Integer> FIFO = new ArrayBlockingQueue<Integer>(4);

        int i = 0;

        while ( i < 10 ){

            if (!FIFO.offer(i)){
            // You can pipe the head of the queue anywhere you want to
                FIFO.remove();
                FIFO.offer(i);
            }
            System.out.println(FIFO.toString());
            i++;

        }
    }

    }
Sky
  • 11
  • 1
0

LinkedTransferQueue is a blocking, unbounded queue that doesn't enforce strict FIFO ordering. It will only block when taking from an empty queue, but never on adding to one. You could add a soft cap to evict elements by adding either a size or read & write counters.

Depending on your requirements, you may be able to write a custom lock-free ring buffer.

Ben Manes
  • 9,178
  • 3
  • 35
  • 39
  • TransferQueue is cool but still unbound and the unbound ones do suck badly as there is no telling if anything goes amiss. – bestsss Jun 25 '12 at 08:00