views:

56

answers:

2

I've just been messing around with threads in Java to get my head around them (it seems like the best way to do so) and now understand what's going on with synchronize, wait() and notify().

I'm curious about whether there's a way to wait() on two resources at once. I think the following won't quite do what I'm thinking of (edit: note that the usual while loops have been left out of this example to focus just on freeing up two resources):

synchronized(token1) {
    synchronized(token2) {
        token1.wait();
        token2.wait(); //won't run until token1 is returned
        System.out.println("I got both tokens back");
    }
}

In this (very contrived) case token2 will be held until token1 is returned, then token1 will be held until token2 is returned. The goal is to release both token1 and token2, then resume when both are available (note that moving the token1.wait() outside the inner synchronized loop is not what I'm getting at).

A loop checking whether both are available might be more appropriate to achieve this behaviour (would this be getting near the idea of double-check locking?), but would use up extra resources - I'm not after a definitive solution since this is just to satisfy my curiosity.

Edit Let's just for the sake of argument say that the two tokens here represent two distinct resources that the thread must use at the same time, and that some other threads will need both at the same time.

A: 

No, not with a standaad Java lock. Although I guess you could construct such a lock.

wait should be called within a while loop (wait may spuriously wakeup, and in most situations you would want the loop anyway). So some kind of flag would make more sense.

Tom Hawtin - tackline
I suppose you mean some kind of flag instead of the second lock? Something like `while (!flag) {token1.wait();}`
Dr. Monkey
+1  A: 

The example doesn't include the condition upon which the waiting will be performed. Typically, waiting will occur only and until the condition has been met. Generally, I would think that one could accomplish what you are trying to by having a single lock / wait and abstracting the 'token1 and token2' into the conditional logic.

For example

synchronized(object) {
   while ((!token1ConditionMet) && (!token2ConditionMet)) {
       wait();
   }
} 
btreat