简体   繁体   English

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

[英]Deadlock situation using threads in java?

I have created 3 classes,我创建了 3 个类,

  1. class InCharge - Should check the current Balance, while checking Client thread should wait() until InCharge thread finish the testing(15Secs) class InCharge - 应检查当前余额,同时检查Client线程应wait() ,直到InCharge线程完成测试(15 秒)
  2. Class Client - Should withdraw money each 5Seconds, but when InCharge Thread running Client thread should wait until InCharge thread says Notify() Class 客户端 - 应该每 5 秒取款,但是当InCharge线程运行时Client线程应该等到InCharge线程说Notify()
  3. class Bank - Which hold the current balance, and the lock for Synchronized block. class 银行 - 持有当前余额,以及Synchronized块的锁定。

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.根据我的调试,似乎是InCharge发送了Notify()但由于某种原因客户端没有收到通知,我猜问题是因为while(true) ,但我想不出解决方法.

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.银行关闭 5 秒,然后打开,但会立即尝试再次进入同步块以关闭银行。 Sometimes InCharge/bank thread will beat the client thread to get access to synchronized(obj) .有时 InCharge/bank 线程会击败客户端线程以访问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.这是正常的,也是意料之中的,但这意味着在许多周期中,银行会继续休眠(5000),而上一个周期显示的余额相同,并且在这之间没有客户提款代码运行。

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.为了模拟银行的正常工作时间,您可以在 InCharge 线程中同步后添加第二个小 sleep(),此期间将显示客户端更频繁地获取锁以进行提款。 Change InCharge.run() to:将 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) {}
    }
}

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.如果您进一步开发应用程序,您应该尝试 2 个客户端线程,并且需要将notify()更改为notifyAll()以确保所有客户端都有机会使用银行。 Also changing your code to be Runnable instead of extending Thread would make the code clearer.还将您的代码更改为 Runnable 而不是扩展 Thread 将使代码更清晰。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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