java2d死锁_Java多线程——死锁

当一个线程永远地持有一个锁,并且其他线程都尝试获得这个锁时,那么他永远被阻塞,当线程A持有锁L并想获得锁M的同时,线程B持有锁M并同时尝试获得锁L时,那么两个线程将永远的等待下去,这中情况就是简单的死锁的形式,其中多个线程由于存在环路的锁依赖关系而永远的等待下去,那么就存在一个死锁。

1、锁顺序死锁

下面是顺序锁的一个列子,代码如下:

d641ff6561708a83b8708d3765b301392f7.jpg

2002ea8e6e691607f02e6df13f62d0c93b1.jpg

1 packagedeadLock;2

3 public classLeftRightDeadLock {4 private final Object left = newObject();5 private final Object right = newObject();6

7 public void leftRight() throwsException{8 synchronized(left) {9 Thread.sleep(2000);10 synchronized(right) {11 System.out.println("left to right");12 }13 }14 }15

16

17 public void rightLeft() throwsException{18 synchronized(right) {19 Thread.sleep(2000);20 synchronized(left) {21 System.out.println("right to left");22 }23 }24 }25

26 }

View Code

fb3891194016bc66e6aa2f88b0290798825.jpg

2af204f257e11435157f0fd1ba3937422a4.jpg

1 packagedeadLock;2

3 public class LeftRightThread extendsThread {4

5 privateLeftRightDeadLock d;6 publicLeftRightThread(LeftRightDeadLock d){7 this.d =d;8 }9 @Override10 public voidrun() {11 try{12 d.leftRight();13 }catch(Exception ex){14 ex.printStackTrace();15 }16 }17

18 }

View Code

2c0c5fdb7b59ed3a079495e6cbc875c3da6.jpg

6c4607753b845f14cf06e9adfd1125d7f46.jpg

1 packagedeadLock;2

3 public class RightLeftThread extendsThread {4

5 privateLeftRightDeadLock d;6 publicRightLeftThread(LeftRightDeadLock d){7 this.d =d;8 }9 @Override10 public voidrun() {11 try{12 d.rightLeft();13 }catch(Exception ex){14 ex.printStackTrace();15 }16 }17

18 }

View Code

f8ef293b5629313052701cb9e7ec37b654c.jpg

b6e8a64d21e1ae71f6eb2880b8eea2eb484.jpg

1 packagedeadLock;2

3 public classMain {4 public static voidmain(String[] args) {5 LeftRightDeadLock d = newLeftRightDeadLock();6 LeftRightThread t1 = newLeftRightThread(d);7 RightLeftThread t2 = newRightLeftThread(d);8 t1.start();9 t2.start();10 }11 }

View Code

线程t1持有left的锁,并尝试获取得right的锁,而线程t2持有right的锁,并尝试获得left的锁,故产生死锁。产生死锁的原因是:两个线程试图以不同的顺序来获得相同的锁,如果按照相同的顺序来请求锁,那么就不会出现循环的加锁依赖性,因此也就不会产生死锁。

如果所有线程以固定的顺序来获得锁,那么在程序中就不会出现锁顺序死锁的问题

2、动态的锁顺序死锁

有时候,并不能清楚的知道是否在锁顺序上有足够的控制权来避免死锁的发生,看如下转账的代码。

c209f4a552ea1e9a03cc4b3cde994048c47.jpg

26a1b39deb398866314e94cbe57ce7b98d6.jpg

1 public classTransferAccounts {2 public void transferMoney(Account fromAccount, Account toAccount, double amount) throwsException{3 synchronized(fromAccount) {4 synchronized(toAccount) {5 if(fromAccount.getBalance() - amount < 0){6 throw newException();7 }8 else{9 fromAccount.setBalance(amount);10 toAccount.add(amount);11 }12 }13 }14 }15 }

View Code

bcae83cad3a4fb8f0365e517d172b15157c.jpg

edd93eab3dbf22d8416a798a87991514046.jpg

1 public classAccount {2

3 //金额

4 private doublebalance;5

6 public doublegetBalance() {7 returnbalance;8 }9

10 public void setBalance(doublebalance) {11 this.balance =balance;12 }13 public void add(doubleamount){14 balance +=amount;15 }16 public void subtra(doubleamount){17 balance -=amount;18 }19

20 }

View Code

上面代码是资金从一个账户转到另一个账户的简单实现,在开始转账之前要获得这两个Account对象的锁,以确保通过原子方式来更新两个账户的中余额。所有的线程似乎都是按照顺序锁来获得锁,但是事实上锁的顺序取决于转给函数transferMoney参数顺序,而这些参数又取决于外部的输入,如果两个线程同时调用transferMoney,其中一个线程从X向Y转账,另一个线程从Y向X转账,有可能发生死锁:

线程A:transferMoney(xAccount, yAccount);

线程B:transferMoney(yAccount, xAccount);

为了防止这种情况发生,必须按照顺序来获取锁。如下代码:

e0d6e9eda8ac0556cfe2ef7b0e4538b462c.jpg

300415921b33c3e360c3be876310c65faae.jpg

1 public classTransferAccounts {2 private static final Object tieLock = newObject();3

4 public voidtransfer(Account fromAccount, Account toAccount,5 double amount) throwsException {6 if (fromAccount.getBalance() - amount < 0) {7 throw newException();8 } else{9 fromAccount.setBalance(amount);10 toAccount.add(amount);11 }12 }13 public voidtransferMoney(Account fromAccount, Account toAccount,14 double amount) throwsException{15 int fromHash =fromAccount.hashCode();16 int toHash =toAccount.hashCode();17 if(fromHash toHash){24 synchronized(toAccount) {25 synchronized(fromAccount) {26 transfer(fromAccount, toAccount, amount);27 }28 }29 }else{30 synchronized(tieLock) {31 synchronized(fromAccount) {32 synchronized(toAccount) {33 transfer(fromAccount, toAccount, amount);34 }35 }36 }37 }38 }39

40 }

View Code

在极少数的情况下,两个对象可能拥有相对的hashCode值,这时必须通过添加额外的锁来,在获得两个Account的锁之前,必须先获得这个额外的锁。从而消除死锁的发生。

3、死锁的避免与诊断

(1) 如果一个程序每次至多只能获取一个锁,那么就不会产生锁顺序死锁。

(2) 如果必须获取多个锁,那么设计时必须考虑锁的顺序,如果按照固定的顺序来获取锁,就不会发生锁顺序死锁。

(3)支持定时锁,例如显示使用Lock类中的定时tryLock功能来代替内置锁,显示锁可以指定一个超时时限,在等待超过某个时间后tryLock会返回一个失败的信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值