views:

383

answers:

5

Q1. What is a condVar in Java? If I see the code below, does a condition variable necessarily have to be within the 'mutex.acquire()' and 'mutex.release()' block?

public void put(Object x) throws InterruptedException {
   mutex.acquire();
   try {
      while (count == array.length)
      notFull.await();
      array[putPtr] = x;
      putPtr = (putPtr + 1) % array.length;
      ++count;
      notEmpty.signal();
  }
  finally {
     mutex.release();
  }
}

I have three threads myThreadA, myThreadB, myThreadC running which call the same function commonActivity() which triggers the function myWorkReport() e.g.

public void myWorkReport(){
    mutexMyWork.acquire();
    try{
         while(runMyWork){
             doWork();
             conditionMyWork.timedwait(sleepMyWork);
         }
    }
    finally{
       mutexMyWork.release()
    }    
}

public void commonActivity(){
    try{
        conditionMyWork.signal(); 
    }finally{
        //cleanup
    }   
}

public void myThreadA(){
    mutexA.acquire();
    try{
        while(runningA){    //runningA is a boolean variable, this is always true as long as application is running
            conditionA.timedwait(sleepA);
            commonActivity();
        }
    }
    finally{
        mutexA.release();
    }
}


public void myThreadB(){
    mutexB.acquire();
    try{
        while(runningB){    //runningB is a boolean variable, this is always true as long as application is running
            conditionB.timedwait(sleepB);
            commonActivity();
        }
    }
    finally{
        mutexB.release();
    }
}

public void myThreadC(){
    mutexC.acquire();
    try{
        while(runningC){    //runningC is a boolean variable, this is always true as long as application is running.
            conditionC.timedwait(sleepC);
            commonActivity();
        }
    }
    finally{
        mutexC.release();
    }
}

Q2. Is using timedwait a good practice. I could have achieved the same by using sleep(). If using sleep() call is bad, Why?

Q3. Is there any better way to do the above stuff?

Q4. Is it mandatory to have condition.signal() for every condition.timedwait(time);

A: 

Q1. I believe by "condition variable", you're referring to something you check to determine the condition that you waited on. For example - if you have the typical producer-consumer situation, you might implement it as something like:

List<T> list;

public T get()
{
    synchronized (list)
    {
         if (list.get(0) == null)
         {
             list.wait();
         }
         return list.get(0);
    }
}

public void put(T obj)
{
    synchronized (list)
    {
         list.add(obj);
         list.notify();
    }
}

However, due to the potential of spurious thread wakeups, it is possible for the consumer method to come out of the wait() call while the list is still empty. Thus it's good practice to use a condition variable to wait/sleep/etc. until the condition is true:

while (list.get(0) == null)
{
    list.wait();
}

using while instead of if means that the consumer method will consumer method will only exit that block if it definitely has something to return. Broadly speaking, any sleep or wait or blocking call that was triggered by a condition, and where you expect the condition to change, should be in a while block that checks that condition every loop.

In your situation you're already doing this with the while (count == array.length) wrapper around notFull.await().

Q2. Timed wait is generally a good practice - the timeout allows you to periodically perform a sanity check on your environment (e.g. has a shutdown-type flag been flipped), whereas a non-timed wait can only be stopped by interruption. On the other hand, if the wait is going to just keep blocking anyway until the condition is true, it makes little difference it it wakes up every 50 ms (say) until the notify() happens 2 seconds later, or if it just blocks constantly for those 2 seconds.

As for wait() vs sleep() - the former is generally preferable, since it means you get woken up as soon as you are able to take action. Thread.sleep(500) means that this thread is definitely not doing anything for the next 500ms, even if the thing it's waiting for is ready 2ms later. obj.wait(500) on the other hand would have been woken up 2ms into its sleep and can continue processing. Since sleeps introduce unconditional delays in your program, they're generally a clunkier way to do anything - they're only suitable when you're not waiting on any specific condition but actually want to sleep for a given time (e.g. a cleanup thread that fires every 60 seconds). If you're "sleeping" because you're waiting for some other thread to do something first, use a wait() (or other synchronous technique such as a CountDownLatch) instead.

Q3. Pass - it looks like there's a lot of boilerplate there, and since the code doesn't have any comments in and you haven't explained what it's supposed to do and how it's meant to behave, I'm not going to try and reverse-engineer that from what you're written. ;-)

Andrzej Doyle
A: 

Q1. Condition variables are part of monitors facility which is sometimes used for threads synchronization. I don't recognize this particular implementations but usually conditional variables usage must be done in the critical section, thus mutex.acquire and release are required.

Q2. timedwait waits for signal on condition variable OR time out and then reqcquires critical section. So it differs from sleep.

Q3. I am not sure, but I think you may use built-in monitors functionality in java: synchronized for mutual exclusion and wait and notify instead of cond vars. Thus you will reduce dependencies of your code.

elder_george
+2  A: 

Q1: A Condition object is associated (and acquired from) a Lock (aka mutext) object. The javadoc for the class is fairly clear as to its usage and application. To wait on the condition you need to have acquired the lock, and it is good coding practice to do so in a try/finally block (as you have). As soon as the thread that has acquired the lock waits on a condition for that lock, the lock is relinquished (atomically).

Q2: Using timed wait is necessary to insure liveness of your program in case where the condition you are waiting for never occurs. Its definitely a more sophisticated form, and it is entirely useless if you do not check for the fact that you have timed out and take action to handle the time out condition.

Using sleep is an acceptable form of waiting for something to occur, but if you are already using a Lock ("mutex") and have a condition variable for that lock, it make NO sense not to use the time wait method of the condition:

For example, in your code, you are simply waiting for a given period but you do NOT check to see if condition occurred or if you timed out. (That's a bug.) What you should be doing is checking to see if your timed call returned true or false. (If it returns false, then it timed out & the condition has NOT occured (yet)).

public void myThreadA(){
    mutexA.acquire();
    try{
        while(runningA){    //runningA is a boolean variable
            if(conditionA.await (sleepATimeoutNanos))
                commonActivity();
            else {
                // timeout!  anything sensible to do in that case? Put it here ...
            }
        }
    }
    finally{
        mutexA.release();
    }
}

Q3: [edited] The code fragments require a more detailed context to be comprehensible. For example, its not entirely clear if the conditions in the threads are all the same (but am assuming that they are).

If all you are trying to do is insure commonActivity() is executed only by one thread at a time, AND, certain sections of the commonActivity() do NOT require contention control, AND, you do require the facility to time out on your waits, then, you can simply use a Semaphore. Note that sempahore has its own set of methods for timed waits.

If ALL of the commonActivity() is critical, AND, you really don't mind waiting (without timeouts) simply make commonActivity() a synchronized method.

[final edit:)] To be more formal about it, conditions are typically used in scenarios where you have two or more thread co-operating on a task and you require hand offs between the threads.

For example, you have a server that is processing asynchronous responses to user requests and the user is waiting for fulfillment of a Future object. A condition is perfect in this case. The future implementation is waiting for the condition and the server signals its completion.

In the old days, we would use wait() and notify(), but that was not a very robust (or trivially safe) mechanism. The Lock and Condition objects were designed precisely to address these shortcomings.

(A good online resource as a starting point)

Buy and read this book.

thanks alphazero for such detailed explaination. myThreadA, myThreadB, myThreadC are totally all different but they have a common section called commonActivity (you can say all of the three after processing call a common method which prints logs or reports or events). The common activity happens only if the processing by any of the thread is successful otherwise will not... so the commonActivity is triggered using condition variables.Do I make sense??
Devil Jin
So n threads run n distinct tasks, and if *any* of them processed, then the 'commonActivity' is executed. Question remains: is commonActivity invoked once (regardless of how many threads were successful), or, once and only once IF any of the threads was sucessful.
Every thread myThreadA, myThreadB, myThreadC have a while loop whose condition is always true (runningA, runningB, runningC are always true as long as application is up and running. Only during the shutdown runningA, runningB, runningC are toppled to false). This means commonActivity is continuously being invoked by the three Threads continuously.
Devil Jin
Is it a good practice to have mutex.release() in the finally block??
Devil Jin
Its effectively a must. If an exception is thrown, your thread may remain in possession of the lock (depending on where the exception was raised) and you wouldn't want that. The javadoc for Lock discusses this.
A: 

Q1. I think documentation gives quite good description. And yes, to await or signal you should hold the lock associated with the condition.
Q2. timedWait is not in Condition API, it's in TimeUnit API. If you use Condition and want to have a timeout for waiting use await(long time, TimeUnit unit). And having a timeout is generally a good idea - nobody wants a program to hang forever - provided you know what to do if timeout occurs.
Sleep is for waiting unconditionally and await is for waiting for an event. They have different purposes. Q3. I don't know what this code is expected to do. If you want to perform some action cyclically, with some break between each iteration, use sleep instead of conditions.
Q4. As I wrote above conditions don't have timedwait method, they have await method. And calling await means you want to wait for some event to happen. This assumes that sometimes this event does happen and someone signals this. Right?

Tadeusz Kopec
+1  A: 

Q1) The best resource for this is probably the JavaDoc for the Condition class. Condition variables are a mechanism that allow you to test that a particular condition holds true before allowing your method to proceed. In the case of your example there are two conditions, notFull and notEmpty.

The put method shown in your example waits for the notFull condition to become true before it attempts to add an element into the array, and once the insertion completes it signals the notEmpty condition, to wake up any threads blocked waiting to remove an element from the array.

...does a condition variable necessarily have to be within the 'mutex.acquire()' and 'mutex.release()' block?

Any calls to change the condition variables do need to be within a synchronized region, this can be through the build in synchronized keyword, or one of the synchronizer classes provided by the java.util.concurrent package such as Lock. If you did not synchronize the condition variables there are two possible negative outcomes:

  1. A missed signal - this is where one thread checks a condition and finds it does not hold, but before it blocks, another thread comes in, performs some action to cause the condition to become true, and then signals all threads waiting on the condition. Unfortunately, the first thread has already checked the condition and will block anyway, even though it could actually proceed.

  2. The second issue is the usual problem where you can have multiple threads attempting to modify the shared state simultaneously. In the case of your example multiple threads may call put() simultaneously, all of them then check the condition and see that the array is not full and attempt to insert into it, thereby overwriting elements in the array.

Q2) Timed waits can be useful for debugging purposes as they allow you to log information in the event the thread is not woken up via a signal.

Using sleep() in place of a timed wait is NOT a good idea, because as mentioned above you need to call the await() method within a synchronized region, and sleep() does not release any held locks, while await() does. This means that any sleeping thread will still hold the lock(s) they have acquired, causing other threads to block unnecessarily.

Q4) Technically, no you don't need to call signal() if you're using a timed wait, however, doing so means that all waits will not return until the timeout has elapsed, which is inefficient to say the least.

Jared Russell
+1 why condition variables need mutex.acquire() and release();
Devil Jin