views:

43

answers:

2

I am trying to solve the readers-writers problem with writer preference in Java using multi-threading. The following is a stripped down version of what my code does. Will it work?

public PriorityQueue<myClass> pq;
public void foo(){
    myClass obj = new myClass();
    pq.add(obj);
    obj.wait();
    //Actual code
}
public void bar(){
    pq.remove().notify();
}

Assume that the priority queue pq is empty initially and the constructor of the enclosing class calls the constructor of pq. Also, foo is called first and then bar. So when foo is called, it adds obj to the queue and that becomes the front element so that when the remove is called in bar that is the element that is removed. My question is, will "Actual code" be executed? Or am I performing wait() and notify() on two completely different objects? If so, how can I fix it?

A: 

You should note that PriorityQueue is not thread safe... i.e. if foo and/or bar is called concurrently they may irreparably break pq's internal state.

tobyodavies
Assume that I use PriorityBlockingQueue. My problem is still not solved.
Meher
A: 

I'm still trying to parse your question, and so far what I can extract is that you want to implement a priority queue for myClass that exhibits writer preference. Java's off-the-shelf locks don't offer strict writer preference, but if you are OK (and it's probably best) with approximate writer preference, you can use a normal ReentrantReadWriteLock in fair mode.

Having written all this (and thought about the many ways it could go wrong) I really wonder why the java.util.concurrent implementation of PriorityBlockingQueue doesn't meet your need.

The following code is far from tested, but passes my 1:00AM sniff test.

private final PriorityQueue<myClass> pq = ...;
// associated RW lock, in fair mode (==true)
private final ReadWriteLock pqLock = new ReentrantReadWriteLock(true);    
private final Condition pqWriteCondition = pqLock.writeLock().newCondition();    

public void produceNew()
{
    myClass obj = new myClass();
    pqLock.writeLock.lock();
    try { 
      pq.offer(obj);
      pqWriteCondition.notifyAll();
    } finally {
      pqLock.writeLock.unlock();
    } 
    //Actual code
}

public void consumeFirst() {
    myClass consume = null;
    pqLock.readLock.lock();
    try { 
      consume = pq.poll();
      while (consume == null) {
        pqWriteCondition.wait();
        consume = pq.poll();
      }
    } finally {
      pqLock.readLock.unlock();
    } 
    //Actual code

}
andersoj
@andersoj: My code wasn't working because I wasn't using a synchronized block on the proper objects while performing waits and notifies. Your code, I believe, will suffer from something similar.
Meher
Interesting... not that I've tested this carefully, but it's similar to code I have used in production. Usually for an object protected by a read/write lock, a write-lock condition is the correct place to do this. Did you look at the RWLock API?
andersoj
Also, if you're not using j.u.concurrent Locks and Conditions, but instead bare java monitors w/ `wait()` and `notify()`, there's a related question here: http://stackoverflow.com/questions/3903039/wait-and-notify-method-always-illegalmonitorstateexception-is-happen-and-te/3951544#3951544
andersoj
@Meher, oh I see what you're seeing. No, `wait()` and `notify()` work differently on instances of `Condition`, which override the `Object.wait()` default implementations. No `synchronized` is required, but you do need to `.lock()` the appropriate `Lock` as I have done.
andersoj