简体   繁体   中英

Deadlock situation using threads in java?

I have created 3 classes,

  1. class InCharge - Should check the current Balance, while checking Client thread should wait() until InCharge thread finish the testing(15Secs)
  2. Class Client - Should withdraw money each 5Seconds, but when InCharge Thread running Client thread should wait until InCharge thread says Notify()
  3. class Bank - Which hold the current balance, and the lock for Synchronized block.

According to my debugging it's seem to be that InCharge send the Notify() but for some reason Client is not receiving the notice, I'm guessing that the problem is because while(true) , but I cannot think of a way to solve it.

can you please help figure out the problem?

Main:

    public class Main {
    public static void main(String[] args) {
        Object obj = new Object();
        Bank bank = new Bank(100000);

        Client client1 = new Client(obj, bank);
        InCharge inCharge = new InCharge(obj, bank);

        client1.setName("client1");
        inCharge.setName("inCharge");

        client1.start();
        inCharge.start();
    }
}

Bank:

public class Bank {
    private int balance;
    private boolean bankIsClose = false;
    public Bank(int balance) {
        this.balance = balance;
    }
    public int getBalance() {
        return balance;
    }

    public boolean isBankIsClose() {
        return bankIsClose;
    }

    public void setBankIsClose(boolean bankIsClose) {
        this.bankIsClose = bankIsClose;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }
    public synchronized void withdraw(String name, int amount){
        if (this.balance - amount >= 0) {
            this.balance = this.balance - amount;
            System.out.println(name+" "+this.balance + " withdrawed - " + amount);
        }
    }
}

Client:

public class Client extends Thread {
    private Object obj;
    private Bank bank;

    Client(Object obj, Bank bank) {
        this.obj = obj;
        this.bank = bank;
    }

    @Override
    public void run() {
        int randomNumber;
        while (bank.getBalance() > 0) {
            synchronized (obj) {
                randomNumber = ((int) (Math.random() * (5000 - 1000 + 1)) + 1000);
                if (!bank.isBankIsClose()) {
                    try {
                        obj.wait();
                        bank.withdraw(currentThread().getName(), randomNumber);
                    } catch (Exception e) {}
                }
            }
        }
    }
}

InCharge:

public class InCharge extends Thread {
    private Object obj;
    private Bank bank;

    InCharge(Object obj, Bank bank) {
        this.obj = obj;
        this.bank = bank;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                bank.setBankIsClose(true);
                try {
                    System.out.println("Charge is here!, current balance is: " + bank.getBalance());
                    Thread.sleep(5000);
                } catch (InterruptedException e) {}
                bank.setBankIsClose(false);
                obj.notify();
            }
        }
    }
}

You app does run for me without changes, but the bank is not very friendly because of the nature of the bank open/closed loop.

Bank closed for 5 seconds, then opens, but immediately will try to enter the synchronized block again to close the bank. Sometimes InCharge/bank thread will beat the client thread to get access to synchronized(obj) . This is normal and expected, but this means that on many cycles the bank continues its sleep(5000) with same balance displayed by the previous cycle, and no client withdrawal code gets run in between.

To simulate normal hours of a bank you could add a second small sleep() after the synchronised in the InCharge thread, this period would show client getting the lock more frequently in order to make withdrawals. Change InCharge.run() to:

public void run() {
    while (true) {
        synchronized (obj) {
            bank.setBankIsClose(true);
            try {
                System.out.println("Charge is here!, current balance is: " + bank.getBalance());
                Thread.sleep(5000);
            } catch (InterruptedException e) {}
            bank.setBankIsClose(false);
            System.out.println("Now the bank is open for business");
            obj.notify();
        }

        // Simulate a period of bank being open:
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
    }
}

If you develop the app further you should try 2 client threads, and will need to change notify() to notifyAll() to ensure all clients have a chance to use the bank. Also changing your code to be Runnable instead of extending Thread would make the code clearer.

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