0

I tried to let two threads mutually print out something, but the result I get was:

0
Exception in thread "Thread-0" wait in decrement
java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at thread.Multithread2.increment(Multithread2.java:38)
    at thread.Multithread2.run(Multithread2.java:18)
    at java.lang.Thread.run(Unknown Source)

I've already included shared object in synchronized block and invoked wait() / notify() on this object. I don't know why it still throws exception.

public class Multithread2 implements Runnable {

    private Integer integer;
    private int method;

    public Multithread2(Integer integer, int method) {
        this.integer = integer;
        this.method = method;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(20);
            for(int i = 0; i < 5; i++) {
                if(method == 1) {
                    increment();
                } else {
                    decrement();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void increment() throws InterruptedException {
        synchronized(integer) {
            while(integer > 0) {
                integer.wait();
            }
            System.out.println(integer);
            integer++;
            integer.notify();
        }
    }

    public void decrement() throws InterruptedException {
        synchronized(integer) {
            while(integer <= 0) {
                integer.wait();
            }
            System.out.println("decrement: " + integer);
            integer--;
            integer.notify();
        }
    }
}

Main method:

Integer integer = new Integer(0);
Thread t1 = new Thread(new Multithread2(integer, 1));
t1.start();
Thread t2 = new Thread(new Multithread2(integer, 2));
t2.start();
1
  • 1
    integer++ is the same as integer = integer + 1. You are not calling notify() on the same integer you are synchronized on. Commented Oct 29, 2016 at 8:25

1 Answer 1

2
integer++

is equivalent to

integer = Integer.valueOf(integer.getValue() + 1);

So it initializes the integer variable with a different Integer instance. Integer is immutable, so its state can't change. Since you call notify() on this new Integer instance, and you haven't acquire the lock on this new instance, you get that exception.

Use your own, mutable, thread-safe, Counter class. Synchronizing on shared, immutable, Integer instances is a terrible idea. A good rule of thumb, by the way, is to make the fields on which you synchronize final. Doing that would cause a compilation error, and a compilation error is your friend in this situation, provided that you pay attention to what is is actually saying to you.

Sign up to request clarification or add additional context in comments.

6 Comments

Or just AtomicInteger I suppose.
Yes you could use that, too.
"Doing that would cause a compilation error." ... and a compilation error is your friend in this situation, provided that you pay attention to what is is actually saying to you.
@StephenC and you don't just click on the IDE's "remove final declaration" hint without bothering to read the error in the first place...
@StephenC thanks, that makes it clearer. I have added your comment to the answer, hope you don't mind.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.