8

I tried to create a test where I tried to force a race condition (or at least to increase the probability of its occurrence) and I've used a CountDownLatch.

The problem is that I get a java.lang.IllegalMonitorStateException at my CountDownLatch.wait(). I'm certainly misusing the CountDownLatch and I'm surely not creating this test in a clever way.

This simple code reproduces my idea and my problem (I also have a gist):

import java.util.*;
import java.util.concurrent.*;

public class Example {

    private static BusinessLogic logic;

    public static void main(String[] args) {
        final Integer NUMBER_OF_PARALLEL_THREADS = 10;
        CountDownLatch latch = new CountDownLatch(NUMBER_OF_PARALLEL_THREADS);
        logic = new BusinessLogic();

        // trying to force the race condition
        List<Thread> threads = new ArrayList<Thread>(NUMBER_OF_PARALLEL_THREADS);
        for (int i=0; i<NUMBER_OF_PARALLEL_THREADS; i++) {
            Thread worker = new Thread(new WorkerRunnable(latch));
            threads.add(worker);
            worker.start();
        }

        for (int i = 1; i <= NUMBER_OF_PARALLEL_THREADS; i++) {
            try {
                threads.get(i).wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Just a dummy business logic class.
     * I want to "force" a race condition at the method doSomething().
     */
    private static class BusinessLogic {
        public void doSomething() {
            System.out.println("Doing something...");
        }
    }

    /**
     * Worker runnable to use in a Thead
     */
    private static class WorkerRunnable implements Runnable {
        private CountDownLatch latch;

        private WorkerRunnable(CountDownLatch latch) {
            this.latch = latch;
        }

        public void run() {
            try {
                // 1st I want to decrement the latch
                latch.countDown();
                // then I want to wait for every other thread to 
                latch.wait(); // the exception is thrown in this line.
                // hopefully increase the probability of a race condition...
                logic.doSomething();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

The javadoc of the CountDownLatch.wait() states that the IllegalMonitorStateException is thrown if the current thread is not the owner of the object's monitor. But I'm afraid I'm not understanding what this mean, nor I am able to figure how could I recreate my code to avoid this exception.

EDIT: with the tips provided in the answers, I've created a new version of the example above and I've stored in this gist. I don't have any exceptions now.

3 Answers3

24

Try await(), not wait().

await() will wait until the latch reaches zero. wait() is unrelated to latches, and is not what you want in your WorkerRunnable. But FYI, in order to call wait() without getting an exception, you have to own an object's monitor, and to become the owner, you have to be in a block that's synchronized on that object.

hearnden
  • 522
  • 2
  • 8
2

Your controller thread (usually the main/ui thread) should do the waiting, while the worker threads do the countdown-ing.

You should start the threads from your main thread and insert the latch.await() call there - right after you've started them. Each worker thread should call latch.countdown() upon completion.

When allthreads have called countdown() the CountDownLatch will exit latch.await()in the main thread and transfer the control of execution to it (the code after latch.await() will start executing).

So basically you need to move the await() to the main program right after you've started the worker threads.

EDIT: You should also remove the Thread.wait() calls because that is another multithreading framework - wait/notify and it is much more low-level than using a CountDownLatch (Unless you need it for your simulation. I don't quite understand your test case)

Kaloyan Roussev
  • 14,515
  • 21
  • 98
  • 180
  • Thanks for your tips! :) I want every thread to block before they call the business logic method so that they all execute it "at the same time". If I move the await() to the main thread, I won't have any means of blocking the threads before calling BusinessLogic.doSomething(). –  Dec 03 '15 at 13:44
  • You should move the await there, because a single thread cannot call countdown and await. You could make those threads block by calling Thread.wait(), instead of latch.await() – Kaloyan Roussev Dec 03 '15 at 13:49
  • Hm, I see. So, even tough I was able to create a version of the sample code from the question without exceptions (see my edit) I might not be achieving the result I hope? –  Dec 03 '15 at 13:53
0

When trying to call wait() an any object you'll have to have the monitor of that object.

Object o = new Object();
o.wait();

will cause an IllegalMonitorStateException.

You have to synchronize on that object in order to be able to call wait():

Object o = new Object();
synchronized(o) {
    o.wait();
}
ParkerHalo
  • 4,341
  • 9
  • 29
  • 51