0

I have set the value of the flag, but the result is not 'add' and 'sub' alternates. Why? When I look at the result, it has executed twice the 'sub' method. But when the 'sub' method ended, the value of the flag will be set 'false'. But as a result, it printed "subxxxxx" twice continuously.

class Resource {
    private boolean flag = true;
    private int num = 0;

// At here I have declared an add()
    public synchronized void add() throws InterruptedException {
        if (this.flag == false) {
            super.wait();
        }
        Thread.sleep(100);
        this.num++;
        System.out.println("addition:"+Thread.currentThread().getName() + this.num);
        this.flag = false;
        super.notifyAll();
    }

// At here I have declared an sub()
    public synchronized void sub() throws InterruptedException {
        if (this.flag == true) {
            super.wait();
        }
        Thread.sleep(200);
        this.num--;
        System.out.println("subtraction:"+Thread.currentThread().getName() + this.num);
        this.flag = true;
        super.notifyAll();
    }
}

/*
* I will test it with multiple threads. For example:
*new Thread(ad, "add").start();
*new Thread(ad, "add").start();
*new Thread(sub, "sub").start();
*new Thread(sub, "sub").start();
*When threads start. it will execute alternately. For example:
Thread add:0
Thread sub:-1
Thread add:0
Thread sub:-1
Thread add:0
Thread sub:-1
Thread add:0
Thread sub:-1
But the result is like this:
Thread add:0
Thread sub:-1
Thread sub:-2
Thread add:-1
Thread sub:-3
Thread sub:-4
Why?Why?Why?
*/
        new Thread(ad, "add").start();
        new Thread(ad, "add").start();
        new Thread(sub, "sub").start();
        new Thread(sub, "sub").start();
    }
}
JiexiSu
  • 11
  • 3

1 Answers1

0

You seem to assume that when your wait() call finishes, that the flag has changed to what you wanted to have before you called wait(). There is no such guarantee, especially since you have more than two threads involved. You should check if you need to continue waiting. Also see Wait until boolean value changes it state

But in general, these constructs are too low-level to use (unless you want to learn the nitty-gritty) and you should look at the concurreny utils package for easier higher-level constructs (like Queues, Latches, Conditions).

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • I have a question. I assume that the value of the flag is false now. I think the thread about 'sub()' must wait. I see what's your mean is when I change the value of 'flag' it will occur one sub() is running another sub() will be waked. But the method is modified by keyword 'synchronized'. Will that happen? – JiexiSu Jan 26 '20 at 09:01
  • Now, I only want to implement this case with add() and sub() executing alternately. I know that there are some errors in my codes. But I do not know where the error is. – JiexiSu Jan 26 '20 at 09:11
  • If you want them to alternate, you have to make sure that you check that flag before resuming. Replace `if (flag == false) { wait();}` with `while (flag == false) { wait();}` – Thilo Jan 26 '20 at 10:03
  • I don't know the difference between them. The method is modified by 'synchronized'. So, it will only one thread call sub() one time. Why? But The result was exactly what I expected – JiexiSu Jan 26 '20 at 10:20
  • When you `wait()` you give up the lock and another thread can enter the synchronized block. – Thilo Jan 26 '20 at 10:27
  • I got it. Thank you very much. – JiexiSu Jan 26 '20 at 10:33