0

From the BlockingQueue documentation:

Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a BlockingQueue happen-before actions subsequent to the access or removal of that element from the BlockingQueue in another thread.'

QUESTION: What does it mean? What are the actions prior to placing? Are they ones that appear before put() invokation in the program code or what?

To provide some example, let's consider the following method that publishes objects into a shared BlockingQueue

public class Person{
    private String name;
    private int age;
    //Maybe it's not a good idea to sttore such Date in Person
    //but let's leave it that way
    private Date processingDate;
    //etc..
    //GET, SET, toString
}

public class MyClass{
    private final BlockingQueue<Person> personsToProceed = new LinkedBlockingQueue(1000);

    public void submitPerson(Person p){
         p.setProcessingDate(new Date());
         //Make some other changes on p
         personsToProceed.put(p);
    }

    public void processPerson(){
        Person p = personsToProceed.take();
        //persist it into a DB
    }
}

Judging by the LinkedBlockingQueue.put() implementation I would not say that p.setProcessingDate(new Date()); and personsToProceed.take(); keep happens-before order. Actually (comments ommited):

public void  put(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        int c = -1;
        final ReentrantLock putLock = this.putLock;
        final AtomicInteger count = this.count;
        putLock.lockInterruptibly();
        try {
            try {
                while (count.get() == capacity)
                    notFull.await();
            } catch (InterruptedException ie) {
                notFull.signal(); // propagate to a non-interrupted thread
                throw ie;
            }
            insert(e);
            c = count.getAndIncrement();
            if (c + 1 < capacity)
                notFull.signal();
        } finally {
            putLock.unlock();
        }
        if (c == 0)
           signalNotEmpty();
  }

All we can say is that put(p) and take() are in happens-before. But since p.setProcessingDate(new Date()); and put(p) are not, than take() in the processPerson() method is racy with p.setProcessingDate(new Date());

What did I miss?

St.Antario
  • 26,175
  • 41
  • 130
  • 318
  • 1
    "Are they ones that appear before put() invokation in the program code" Yes. – Andy Turner Apr 07 '16 at 16:43
  • 4
    The memory barrier provided by `put()` (or rather `lockInterruptibly()`) ensures that `take()` cannot retrieve a `Person` whose processingDate isn't set. I don't see anything *racy* in that method. – Kayaman Apr 07 '16 at 16:43
  • @Kayaman Is it possible for compiler to move `p.setProcessingDate(new Date());` after the synchronization barrier of `put()`? – St.Antario Apr 07 '16 at 16:44
  • No. The memory barrier guarantees that the `happens-before` is fulfilled, so as you asked in your question, all the operations before `put()` are done by that time. – Kayaman Apr 07 '16 at 16:44
  • @St.Antario: Not barring compiler bugs, at least. That is indeed what the documentation's guarantee is saying. – Dolda2000 Apr 07 '16 at 16:48
  • @Kayaman Of course it cannot. _If x and y are actions of the same thread and x comes before y in program order, then hb(x, y)._ Got it... – St.Antario Apr 07 '16 at 16:49
  • 2
    In Java 5 the Java Memory Model was fixed/improved due to some bugs in earlier versions. I can't remember any problems with the memory model after that. – Kayaman Apr 07 '16 at 16:49
  • Do you understand [what _happens before_ means](http://stackoverflow.com/questions/27636829/happens-before-relation-in-java-memory-model)? – Raedwald Apr 07 '16 at 16:50
  • @Raedwald I didn't understand it correctly. But now yes, I think I do... – St.Antario Apr 07 '16 at 16:50

0 Answers0