我已经汇总了一些Java代码,它们演示了线程中的死锁。就它本身而言,我通常得到2行输出和一个例外,有时在输出行之前和有时之后是预期的。我得到的例外是transfer()方法第一行的NullPointerException。
我遇到的问题是我想知道如何解决这个死锁问题。我已经在StackOverflow上搜索了这个问题并找到了这个页面:
作为解决方案,我尝试了Will Hartung和Dreamcash发布的内容,但在尝试使用synchronize或ReentrantLock对象时仍然会遇到异常。
以下是代码:
帐户类
public class Account {
int id;
double balance;
public Account(int id, double balance){
this.id = id;
this.balance = balance;
}
public void withdraw(double amount){
balance = balance - amount;
}
public void deposit(double amount){
balance = balance + amount;
}
public int getID(){
return id;
}
public double getBalance(){
return balance;
}
}
银行类(单身人士):
public class Bank{
static Bank bank;
Account a1;
Account a2;
private Bank(){}
public static Bank getInstance(){
if(bank==null){
bank = new Bank();
bank.setAccountOne(new Account(1, 100));
bank.setAccountTwo(new Account(2, 100));
}
return bank;
}
public void transfer(Account from, Account to, double amount){
from.withdraw(amount);
to.deposit(amount);
}
public Account getAccountOne(){
return a1;
}
public Account getAccountTwo(){
return a2;
}
public void setAccountOne(Account acc){
a1 = acc;
}
public void setAccountTwo(Account acc){
a2 = acc;
}
}
PersonOne班级:
public class PersonOne implements Runnable {
public void run() {
Bank bank = Bank.getInstance();
Account a1 = bank.getAccountOne();
Account a2 = bank.getAccountTwo();
bank.transfer(a2, a1, 10);
System.out.println("T1: New balance of A1 is " + a1.getBalance());
System.out.println("T1: New balance of A2 is " + a2.getBalance());
}
}
PersonTwo类:
public class PersonTwo implements Runnable {
public void run() {
Bank bank = Bank.getInstance();
Account a1 = bank.getAccountOne();
Account a2 = bank.getAccountTwo();
bank.transfer(a1, a2, 10);
System.out.println("T2: New balance of A1 is " + a1.getBalance());
System.out.println("T2: New balance of A2 is " + a2.getBalance());
}
}
最后,我的主要方法
public static void main(String[] args){
PersonOne p1 = new PersonOne();
PersonTwo p2 = new PersonTwo();
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p2);
t1.start();
t2.start();
}
答案 0 :(得分:8)
我得到的异常是transfer()方法第一行的NullPointerException。
我遇到的问题是我想知道如何解决这个死锁问题。
您的代码无法引发任何死锁。它引起的问题是写入可见性问题:其中一个线程调用惰性Bank
初始化程序而另一个线程看不到写入。
要获得死锁,首先需要任何类型的锁定(synchronized
关键字)。您的特定NPE问题将通过向synchronized
方法添加getInstance
来解决,并且不会引入任何死锁。
我的结论是,你最好的办法是阅读一些关于Java并发性的介绍性材料。
答案 1 :(得分:2)
有许多解决方案,其中一些不太明显的解决方案
答案 2 :(得分:0)
感谢您的回答。
我目前正在学习线程。在上面,我故意试图创建一个死锁,以便我可以学习如何解决死锁问题(如果我真的想要一个执行上述操作的程序,我会避免多线程)。
我使用单例的原因是两个线程试图使用相同的对象。
所以...上面是我用来尝试重新创建死锁的代码,所以我在运行时期待出现问题/异常。我尝试修复它的一种方法是将传输方法重写为:
public void transfer(Account from, Account to, double amount){
synchronized(from){
synchronized(to){
from.withdraw(amount);
to.withdraw(amount);
}
}
}
但是我会在synchronized(from)行上得到NullPointerException。
我也在传输方法中尝试了这个(并且帐户里面有一个ReentrantLock对象)。但是这次我在读取from.getLock()的行上得到一个NullPointerException。unlock()
public void transfer(Account from, Account to, double amount){
while(true){
try{
if(from.getLock().tryLock()){
try{
if(to.getLock().tryLock()){
from.withdraw(amount);
to.withdraw(amount);
break;
}
} finally {
to.getLock().unlock();
}
}
} finally{
from.getLock().unlock();
}
Random random = new Random();
int i = random.nextInt(1000);
try {
Thread.sleep(1000 + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}