简体   繁体   中英

Why are the statements after if statement not running as expected in a synchronized method

I have a simple class with two synchronized methods. One which should withdraw cash and one which should deposit cash.

And then I have another main class with an inner class. Both the main class and the inner class are implementing Runnable, where the main class is running the "withdraw"-method and the inner class running the "deposit"-method.

When that is done I am creating two Threads to run (ie start) the separate methods in the separate "Runnable"-classes.

The class with the synchronized methods have these methods:

package test;

public class ThreadClass {


int amount = 10;


synchronized void withdraw(int amount) {
    System.out.println("going to withdraw...");

    if(this.amount < amount) {
        System.out.println("Less balance..");
        try {
            wait();

        }
        catch(Exception e) {
            e.printStackTrace();
        }

    }
    this.amount+=amount;
    System.out.println("withdrawal completed");
}


synchronized void deposit(int amount) {
    System.out.println("going to deposit...");
    this.amount+=amount;
    System.out.println("deposit completed");
    notify();       
 }
}

and the class which is responsible for implementing Runnable and also running the example application looks like this:

package test;

public class ThreadTest implements Runnable {

@Override
public void run() {

    ThreadClass withDraw = new ThreadClass();
    withDraw.withdraw(20);


}



class Threadtest2 implements Runnable{

@Override
public void run() {
    ThreadClass t10 = new ThreadClass();
    t10.deposit(60);

 }

}

public static void main(String[] args) throws InterruptedException {

    ThreadTest tester = new ThreadTest();
    ThreadTest.Threadtest2 tester2 = tester.new Threadtest2();


    Thread t1 = new Thread(tester);
    t1.start();

    Thread t2 = new Thread(tester2);
    t2.start();





 }

}

So when I run this program I am expecting that the notify()-call in the deposit method should notify the withdraw()-method so that the last lines also get executed, ie

    this.amount+=amount;
    System.out.println("withdrawal completed");

..but the application is keeping running and never get to that line so I have to manually terminate it. Is this not the right way of doing it?

The synchronized methods are synchronized on the current instance of the object. So wait() and notify() should be called on the exact same object. But you create two different instances of the ThreadClass object, so you call wait() and notify() on different objects.

You should create a single instance of ThreadClass and pass it to the threads, eg via a constructor:

public class ThreadTest implements Runnable {

    private ThreadClass account;

    public ThreadTest(ThreadClass account) {
        this.account = account;
    }

    @Override
    public void run() {
        account.withdraw(20);
    }

}

class Threadtest2 implements Runnable{

    private ThreadClass account;

    public Threadtest2(ThreadClass account) {
        this.account = account;
    }

    @Override
    public void run() {
        account.deposit(60);
    }

}

And then initialize them like so:

ThreadClass account = new ThreadClass();

ThreadTest tester = new ThreadTest(account);
ThreadTest.Threadtest2 tester2 = tester.new Threadtest2(account);

Also note that after wait() the condition this.amount < amount could still be true, if the deposit amount was insufficient. So you should check the amount and call wait() in cycle, until this condition is satisfied.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM