0

Sorry for my bad formatting. I am using a notepad to write my programs.

This is a working code. The only question I have is, I have read that notify and wait must be used in a Synchornized block. However, in the following example, wait and notify are not used in a synchronized block and still no error is thrown.

class counthrd implements Runnable {

    Thread thrd;
    String x;
    counthrd cnt1;

    counthrd() {
    }
    boolean suspended;
    boolean stopped;

    counthrd(String s, counthrd cnt1) {
        thrd = new Thread(this, s);
        this.cnt1 = cnt1;
        thrd.start();
        x = s;
    }

    public void run() {

        try {
            System.out.println("Starting " + thrd.currentThread().getName());
            for (int i = 1; i < 100; i++) {
                System.out.print(i + "  ");
                if ((i % 10) == 0) {
                    System.out.println();
                    Thread.sleep(500);
                }
//synchronized(cnt1){
                while (suspended) {
                    System.out.println("going to wait mode");
                    wait();
                    notify();
                }
//}
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    synchronized void suspendme() {
        suspended = true;
        notify();
    }

    synchronized void resumeme() {
        suspended = false;
        notify();
    }
}

class counter {

    public static void main(String args[]) throws InterruptedException {
        counthrd cnt1 = new counthrd();
        counthrd cnthrd1 = new counthrd("thrd 1", cnt1);

        Thread.sleep(1000);
        System.out.println("going to wait mode");
        cnt1.suspendme();
        Thread.sleep(1000);
        System.out.println("resuming");
        cnt1.resumeme();
        Thread.sleep(1000);
    }
}
assylias
  • 321,522
  • 82
  • 660
  • 783
user547453
  • 1,035
  • 6
  • 22
  • 38
  • Does this work for you? Normally, wait() does not need to be locked, however, notify() does. – Kevin Mangold Aug 18 '12 at 23:37
  • 3
    You know, Eclipse is for free. It lets you type the first part of a variable name and come up with the rest. This makes your life easier and lets you use variables with different names than `"thrd"`. It also does the formatting for you. – Maarten Bodewes Aug 18 '12 at 23:41
  • so why is my question down rated? it is a genuine question. – user547453 Aug 19 '12 at 00:01
  • 3
    According to [§17.2.1 of the Java Language Specification](http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.2.1), an `IllegalMonitorStateException` is to be thrown in the case where the thread lacks a lock on the subject of the `wait`. – obataku Aug 19 '12 at 01:00
  • @veer...thanks for pointing me to the right direction. – user547453 Aug 19 '12 at 01:10
  • @veer Please post this as an answer so that I can upvote it properly. – gobernador Aug 19 '12 at 01:31
  • @gobernador except it's not an answer, just a comment :p The answer is that he's never actually calling `wait` at all. – obataku Aug 19 '12 at 02:25
  • 1
    @veer _"The answer is that he's never actually calling `wait` at all."_ So post that. – gobernador Aug 19 '12 at 02:28

1 Answers1

3

See my comment. Since IllegalMonitorStateException is never thrown, we know that wait is never being called.

Notice you have two instances of counthrd...

counthrd cnt1 = new counthrd();
counthrd cnthrd1 = new counthrd("thrd 1", cnt1);

See which instance you're calling suspendme and resumeme on?

Thread.sleep(1000);
System.out.println("going to wait mode");
cnt1.suspendme();
Thread.sleep(1000);
System.out.println("resuming");
cnt1.resumeme();
Thread.sleep(1000);

cnt1 is initialized using your no-arg constructor, seen here:

counthrd() {
}

The point is that cnt1 never actually starts its own thread. It never does anything, really. cnthrd1 is the one that starts a thread, as seen here:

counthrd(String s, counthrd cnt1) {
    thrd = new Thread(this, s);
    this.cnt1 = cnt1;
    thrd.start();
    x = s;
}

The point to make is that suspended is an instance field, and not shared between cnt1 and cnthrd1. Modifying cnt1.suspended will not cause cnthrd1 to go into "wait mode". wait is never called, and thus the exception is never thrown.

To demonstrate, try calling suspendme and resumeme on cnthrd1, instead... :-)

C:\dev\scrap>javac counter.java

C:\dev\scrap>java counter
Starting thrd 1
1  2  3  4  5  6  7  8  9  10
11  12  13  14  15  16  17  18  19  20
going to wait mode
going to wait mode
java.lang.IllegalMonitorStateException
resuming

That being said, I figured I'd suggest you do some stuff that your code should be doing.

  1. Declare suspended as volatile. Without some explicit memory ordering guarantees, there's no guarantee when or even if cnthrd1 reads the updated value of suspended.
  2. Ditch the cnt1 field and instance; there's no reason for them. Get rid of that empty constructor, too.
  3. Thread.currentThread is a static method; you don't need to use an instance for it. That all aside, thrd is guaranteed to equal Thread.currentThread here.
  4. counthrd.x is equal to thrd.getName; why not just use x instead?
  5. Use some better, more descriptive names. For example, instead of x, why not name? Instead of thrd, why not thread? Instead of counthrd, why not CountingThread?
  6. You only need to call notify in resumeme, not suspendme. (in fact, calling notify in suspendme could accidentally trigger an InterruptedException if the thread is sleeping i.e. when (i % 10) == 0)
  7. You also don't want notify in the while (suspended) loop. Your while loop can actually be turned into an if statement, too, now.
  8. As previously stated, you need synchronized (this) around your code that calls while.
  9. Avoid doing real logic in the constructor, e.g. thrd.start().
  10. suspend doesn't need to be synchronized. resume doesn't need to be synchronized, either; only the wait and notify calls require it.

You can find a modified version of your example that works properly here.

Community
  • 1
  • 1
obataku
  • 29,212
  • 3
  • 44
  • 57
  • @veer...Thank you so much for taking your time and explaining in detail. I actually wanted to create 2 threads on `counthrd` to interleave the output and I wanted a common reference for these 2 threads to use. So that is why I was trying to create `cnt1` instance. Also in the synchornized block I want to synchronize on this common reference `cnt1` and not on `this` an instance for each thread. Anyways, I found that whatever crazy thing I was trying to do, I still need to use `this` in the synchornized block. I also looked at the modified version. Thanks again. – user547453 Aug 19 '12 at 21:29