0

I have 6 threads accessing one common queue container, they have this in their run() method:

if (queue.size() != 0) {
    Element e = queue.remove();
    //code

It works as intended almost every time, however, once in a while thread switches just between the if check and remove() method, so some other thread gets the element and this thread gets a NoSuchElementException. How do i make sure that between those two lines of code threads won't switch?

  • 1
    You need to syncronise your threads https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html – litelite Aug 03 '17 at 14:52
  • Or you can use a thread safe queue https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html – litelite Aug 03 '17 at 14:53
  • [Java Queue implementations, which one?](https://stackoverflow.com/q/1301691/669576) – 001 Aug 03 '17 at 14:55
  • @litelite, Using a thread-safe queue is _not_ a substitute for synchronizing higher-level code that uses the queue. Making a thread-safe program is not as simple as just building it from thread-safe objects. – Solomon Slow Aug 03 '17 at 18:18
  • @jameslarge Since the queue seems to be the only resource shared between threads it will be enough for his case. However, it will need some small tweeks to adapt the code to the new queue. And it is also what the two other answers are saying... – litelite Aug 03 '17 at 18:23
  • My point is, you are offering a very broad solution (just use a thread-safe implementation of the interface) to a very specific problem (wants to make a certain sequence of method calls into an atomic operation.) Yeah, there _is_ at least one way to use `ArrayBlockingQueue` or some such without any additional synchronization to solve _this_ particular problem, but that is not generally the case. – Solomon Slow Aug 03 '17 at 18:30

2 Answers2

3

The two main options are:

  • making the two statements atomic, for example by using a synchronized block
  • using a concurrent collection.

In your case, you could use a BlockingQueue which has several methods that could solve your problem (see the table in the javadoc). BlockinQueue::take seems to be a good candidate based on the information you have provided.

assylias
  • 321,522
  • 82
  • 660
  • 783
0

Assuming it's a BlockingQueue (which it should be to be properly thread safe) you should probably use poll(long,TimeUnit). This should atomically check if there is an element in the queue withing the time period and return it if there is one (or null if there isn't).

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213