2

If I want to pop the head of a LinkedBlockingQueue, I call .poll(). This returns null if the queue is empty. If I want it to block until the queue is nonempty, I can instead call .take(), which will always return a value, and blocks as long as necessary.

If I want to view the head of a LinkedBlockingQueue (without mutating it), I call .peek(). This returns null if the queue is empty. If I want it to block until the queue is nonempty, I......... do what?

I want to block until the queue is nonempty, but I don't want to mutate the queue. I just want to peek.

Currently I just have:

while (queue.isEmpty()) {
    Thread.sleep(1);
}
lurf jurv
  • 237
  • 1
  • 10
  • 1
    You could use another concurrency primitive to block on, and have the threads that put elements in the queue notify on that. This sounds a bit odd design, would you care to elaborate on your use case? Why would you not take the element from the queue? If there's another thread that's blocked on `take()`, then the design isn't very robust, and if there isn't another thread, there shouldn't be a reason to leave the element in the queue. – Kayaman Jul 03 '20 at 06:26
  • why you just dont define a callback, so you can get notified when the collection has data??? – ΦXocę 웃 Пepeúpa ツ Jul 03 '20 at 06:28
  • 1
    You could use a Deque and put the element you get back, but that's a very ugly solution. Is there no way you can restructure so that you wait when you want data? – tgdavies Jul 03 '20 at 06:30
  • If you do `.take()`, the **notifying-thread** will be _busy waiting_ -- unnecessary CPU cycles. If you sleep the thread (as in the question), it has chances of _missing signal_ (depends: If once empty, is the work done or it can get more tasks?). Doing `.poll()` can immediately let you know if the thread is empty and you signal the **notifying-thread** to wake up. Something like, `if ((val = q.poll()) == null) {condition.signal()`}. And, the **notifying-thread** has `while(true) { condition.await(); //woke up, do work and go to await again` – adarsh Jul 03 '20 at 07:04
  • You could use something like a [TransferQueue](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/TransferQueue.html) where you take from your blocking queue, and then transfer it to any consumers. Otherwise, you're sleeping for 1ms vs checking 'isEmpty' odds are you'll miss when an object is added. – matt Jul 03 '20 at 07:05
  • I think this will help you https://www.tutorialspoint.com/java/lang/object_wait.htm – MissingSemiColon Jul 03 '20 at 08:11
  • @Kayaman Sure. The use case is that it is a job queue. Each job is sent over a socket. However, it is fallible. The worker crashes about once a day, or needs to be updated. So, I want to wait until there is a job on the queue, then send the job on the socket, and only once the job is completed successfully do I actually pop it from the queue. If the job fails (throws an IOException) I just want it to retry in a minute or two. I also considered taking from the queue, and readding it if it failed, but that is unacceptable because it reorders the job from first to last. – lurf jurv Jul 04 '20 at 00:02
  • @matt "Otherwise, you're sleeping for 1ms vs checking 'isEmpty' odds are you'll miss when an object is added." Hm? What does this mean? I do not mind if the job is delayed by 1 millisecond because it takes many seconds to complete. I don't think this will miss an object, how could it? This is the only thread that is taking from the queue, but there are other threads adding jobs to the queue. – lurf jurv Jul 04 '20 at 00:03
  • I have flagged this as duplicate. – lurf jurv Jul 04 '20 at 00:06
  • @lurfjurv When I think of a blocking queue, I assume something else is waiting to take from it. ie You have a consumer somewhere down the line. So when an object gets added to your queue, your check needs to happen between the object being added but before the consumer removes it. In that situation, your monitoring loop will probably be asleep for the duration of adding the object and removing it. – matt Jul 04 '20 at 09:07
  • From your repy to Kayaman's comment, I think re-adding it is a good solution. If you need to add it to the front, maybe use a [LinkedBlockingDeque](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/LinkedBlockingDeque.html) ? – matt Jul 04 '20 at 09:08

0 Answers0