在 java 中使用线程的死锁情况?

Deadlock situation using threads in java?

我创建了 3 个 classes,

  1. class InCharge - 应该检查当前余额,同时检查 Client 线程应该 wait() 直到 InCharge 线程完成测试(15 秒)
  2. Class 客户端 - 应该每 5 秒取款,但是当 InCharge 线程 运行 Client 线程应该等到 InCharge 线程说 Notify()
  3. class 银行 - 持有当前余额,并锁定 Synchronized 区块。

根据我的调试,似乎是 InCharge 发送了 Notify() 但由于某种原因客户端没有收到通知,我猜测问题是因为 while(true), 想不出办法解决

你能帮忙解决问题吗?

主要:

    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();
    }
}

银行:

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);
        }
    }
}

客户:

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) {}
                }
            }
        }
    }
}

负责人:

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();
            }
        }
    }
}

你的应用程序为我做了 运行 没有改变,但是由于银行 open/closed 循环的性质,银行不是很友好。

Bank 关闭 5 秒,然后打开,但立即将尝试再次进入同步块以关闭 bank。有时 InCharge/bank 线程会击败客户端线程以获得对 synchronized(obj) 的访问权。这是正常的和预期的,但这意味着在许多周期中,银行继续其睡眠(5000),并显示与前一个周期相同的余额,并且没有客户提款代码在其间获得 运行。

要模拟银行的正常工作时间,您可以在 InCharge 线程中的同步之后添加第二个小的 sleep(),这段时间会显示客户端更频繁地获取锁以进行提款。将 InCharge.run() 更改为:

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) {}
    }
}

如果您进一步开发应用程序,您应该尝试使用 2 个客户端线程,并且需要将 notify() 更改为 notifyAll() 以确保所有客户端都有机会使用银行。另外将代码更改为 Runnable 而不是扩展 Thread 将使代码更清晰。