Java线程-死锁的解决方案?
我已经编写了一些Java代码来演示线程中的死锁。就其本身而言,我通常会得到两行输出和一个异常,有时在预期的输出行之前,有时在输出行之后。我得到的异常是transfer()方法第一行的NullPointerException 我遇到的问题是我想知道如何解决这个死锁问题。我在StackOverflow上搜索了此问题,并找到了此页面: 作为解决方案,我尝试了Will Hartung和Dreamcash发布的内容,但在尝试使用synchronize或ReentrantLock对象时仍然会出现异常 代码如下: 科目类别:Java线程-死锁的解决方案?,java,multithreading,thread-safety,deadlock,Java,Multithreading,Thread Safety,Deadlock,我已经编写了一些Java代码来演示线程中的死锁。就其本身而言,我通常会得到两行输出和一个异常,有时在预期的输出行之前,有时在输出行之后。我得到的异常是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;
}
}
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());
}
}
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 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;
}
}
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());
}
}
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 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;
}
}
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());
}
}
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 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;
}
}
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());
}
}
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();
}
我得到的异常是transfer()方法第一行的NullPointerException
我遇到的问题是我想知道如何解决这个死锁问题
您的代码不可能引发任何死锁。它引发的是写可见性问题:其中一个线程调用lazyBank
初始值设定项,而另一个线程没有看到写操作
要获得死锁,首先需要任何类型的锁定(synchronized关键字synchronized
)。通过将synchronized
添加到getInstance
方法,您的特定NPE问题将得到解决,并且不会引入任何死锁
我的结论是,您最好阅读一些关于Java并发性的介绍性材料
我得到的异常是transfer()方法第一行的NullPointerException
我遇到的问题是我想知道如何解决这个死锁问题
您的代码不可能引发任何死锁。它引发的是写可见性问题:其中一个线程调用lazyBank
初始值设定项,而另一个线程没有看到写操作
要获得死锁,首先需要任何类型的锁定(synchronized关键字synchronized
)。通过将synchronized
添加到getInstance
方法,您的特定NPE问题将得到解决,并且不会引入任何死锁
我的结论是,您最好阅读一些关于Java并发性的介绍性材料。有许多解决方案,其中一些不太明显的是
- 使用一个线程,不要使用锁。在本例中,由于锁的开销超过了正在完成的工作,因此只需一个线程,代码将变得更简单、更快
- 因为这只是一个示例,所以只需使用一个全局锁。这不会像多个锁那样执行,但它要简单得多,如果您不需要性能,那么应该做得更简单,更不容易出现错误。这不会导致死锁
- 如果因为这是作业而必须使用多锁,则可以确保始终以相同的顺序锁定。您可以通过按唯一键对对象进行排序并始终首先锁定“第一个”项来完成此操作
- 最后,您可以在第二个帐户上使用tryLock以任何顺序锁定对象。如果失败,请释放两个锁并重试。您可以使用不安全的.tryMonitor()在监视器上执行tryLock
- 使用一个线程,不要使用锁。在本例中,由于锁的开销超过了正在完成的工作,因此只需一个线程,代码将变得更简单、更快
- 因为这只是一个示例,所以只需使用一个全局锁。这不会像多个锁那样执行,但它要简单得多,如果您不需要性能,那么应该做得更简单,更不容易出现错误。这不会导致死锁
- 如果因为这是作业而必须使用多锁,则可以确保始终以相同的顺序锁定。您可以通过按唯一键对对象进行排序并始终首先锁定“第一个”项来完成此操作
- 最后,您可以在第二个帐户上使用tryLock以任何顺序锁定对象。如果失败,请释放两个锁并重试。您可以使用不安全的.tryMonitor()在监视器上执行tryLock
- 谢谢您的回答
我目前正在学习线程技术。在上面,我故意尝试创建一个死锁,这样我就可以学习如何解决死锁问题(如果我真的想要一个实现上述功能的程序,我只需要避免多线程)
我使用单例的原因是两个线程将尝试使用相同的对象
所以。。。上面是我用来尝试重新创建死锁的代码,所以我希望在运行时出现问题/异常。我试图修复它的一种方法是重写transfer方法,使其如下所示:
public void transfer(Account from, Account to, double amount){
synchronized(from){
synchronized(to){
from.withdraw(amount);
to.withdraw(amount);
}
}
}
但是我会在synchronized(from)行上得到一个NullPointerException
我也在transfer方法中尝试了这一点(account中有一个ReentrantLock对象)。但是这次我在读取.getLock().unlock()的行中得到一个NullPointerException
谢谢你的回答 我目前正在学习线程技术。在上面,我故意尝试创建一个死锁,这样我就可以学习如何解决死锁问题(如果我真的想要一个实现上述功能的程序,我只需要避免多线程) 我使用单例的原因是两个线程将尝试使用相同的对象
所以。。。上面是我用来尝试重新创建死锁的代码,所以我希望在运行时出现问题/异常。我试图修复它的一种方法是重写transfer方法,使其如下所示:
public void transfer(Account from, Account to, double amount){
synchronized(from){
synchronized(to){
from.withdraw(amount);
to.withdraw(amount);
}
}
}
但是我会在synchronized(from)行上得到一个NullPointerException
我也