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?