Question

I have the following code:

public void run() {
    while (true) {
        m = q.poll();
        if (m != null) {
            kf.sendMessage(m.topic, m.message);
        }
    }
}

where q is a ConcurrentLinkedQueue. Currently this is eating 100% of my CPU. Is there a more efficient way to wait on a non-blocking queue? I prefer to use a non-blocking queue because I am expecting bursty traffic from the producers on the queue, so I want to maximize performance. Is there a way to relinquish control of the cpu for my thread if q.poll() returns null?

I have the option of switching to a blocking queue, but I am curious what the proper way of doing this is.

Edit - Lots of good responses! Thanks for all your help. For now I'm going to just switch to a linkedblockqueue, and if I start running into performance issues re-evaluate.

Was it helpful?

Solution

If you have nothing else to do, and just want to wait (without using CPU) until data is available, then use a blocking queue. That's exactly what it's made for, with methods like take:

Retrieves and removes the head of the queue represented by this deque (in other words, the first element of this deque), waiting if necessary until an element becomes available.

If you are interesting in how this is implemented, you can take a look at the source for these classes, for example LinkedBlockingQueue#take:

public E take() throws InterruptedException {
    E x;
    int c = -1;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly();
    try {
        while (count.get() == 0) {
            notEmpty.await();
        }
        x = dequeue();
        c = count.getAndDecrement();
        if (c > 1)
            notEmpty.signal();
    } finally {
        takeLock.unlock();
    }
    if (c == capacity)
        signalNotFull();
    return x;
}

As you can see, they maintain a couple of Conditions to signal if the queue is empty or not.

OTHER TIPS

Since you're dealing with bursty behavior, you could wait when you've checked the queue and it's empty.

while (true) {
    m = q.poll();
    if (m != null) {
        kf.sendMessage(m.topic, m.message);
    } else {
        // Queue was empty, wait for a little while
        // Adjust time based on your requirements
        Thread.sleep(100);
    }
}

You should probably benchmark this to make sure it's actually faster than using a BlockingQueue though.

Consider to use BlockingQueue successors. In such case you do not need to iterate over empty list, thread waiting until next element in collection appears


public void run() {
    while (true) {
       m = q.take();
       kf.sendMessage(m.topic, m.message);
    }
}

If you have your heart set on a ConcurrentLinkedQueue, you can do something along the lines of:

public void run() {
  while (true) {
    m = q.poll();
    if (m != null) {
        kf.sendMessage(m.topic, m.message);
    } else Thread.yield();
  }
}

More about Thread.yield. Also consider sleeping for some small amount of time, say 50ms.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top