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
    `integer++` is the same as `integer = integer + 1`. You are not calling `notify()` on the same `integer` you are `synchronized` on. – Boris the Spider Oct 29 '16 at 08:25

1 Answers1

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.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255