在 java 中使用线程的死锁情况?
Deadlock situation using threads in java?
我创建了 3 个 classes,
- class InCharge - 应该检查当前余额,同时检查
Client
线程应该 wait()
直到 InCharge
线程完成测试(15 秒)
- Class 客户端 - 应该每 5 秒取款,但是当
InCharge
线程 运行 Client
线程应该等到 InCharge
线程说 Notify()
- 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 将使代码更清晰。
我创建了 3 个 classes,
- class InCharge - 应该检查当前余额,同时检查
Client
线程应该wait()
直到InCharge
线程完成测试(15 秒) - Class 客户端 - 应该每 5 秒取款,但是当
InCharge
线程 运行Client
线程应该等到InCharge
线程说Notify()
- 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 将使代码更清晰。