并发编程实战死锁读书笔记之吐槽
来源:互联网 发布:软件行业的进项 编辑:程序博客网 时间:2024/05/16 08:34
简单顺序死锁
package com.txr.TransferMoneyDemo;/** * Created by txr on 2017/7/28. */public class LeftRightDeadlock { private final Object left =new Object(); private final Object right=new Object(); public void leftRight(){ synchronized (left){ synchronized (right){ dosomething(); } } } public void rigthLeft(){ synchronized (right){ synchronized (left){ dosomethingElse(); } } }}
显然这样会出现死锁,比如A-->B B--->A,这个时候第一个线程获得了锁A等待获取锁B,第二个线程线程获取了锁B等待获取锁A,这样就形成了死锁
动态的锁顺序死锁
package com.txr.TransferMoneyDemo;import javax.naming.InsufficientResourcesException;/** * Created by zj-db0236 on 2017/7/28. */public class LeftRightDeadlock { public void transferMoney(Account fromAcct,Account toAcct,DollarAmout amout) throws InsufficientResourcesException { synchronized (fromAcct){ synchronized (toAcct){ if(fromAcct.getBalance().compareTo(amout)<0) throw new InsufficientResourcesException(); else{ fromAcct.debit(amout); toAcct.credit(amout); } } } }}
这种死锁也很容易理解,比如 A--->B 另一个线程 B--->A
A:transferMoney(mycount ,yourAccount,1000)
B:transferMoney(yourcount ,myAccount,2000)
和上面一样会发生死锁
通过锁顺序来避免死锁
private static final Object tieLock =new Object(); /** * 以顺序锁的形式来转钱,System.identityHashCode是个本地方法, * 是以引用地址来计算的,HashCode是以值来计算的 * @param fromAcct 转账人 * @param toAcct 被转账人 * @param amout 钱 * @throws InsufficientResourcesException */ public static void transferMoney(final Account fromAcct, final Account toAcct, final DollarAmout amout) throws InsufficientResourcesException { class Helper{ public void transfer() throws InsufficientResourcesException{ //转账人出账 fromAcct.debit(amout); //被转账人入账 toAcct.credit(amout); } } int fromHash =System.identityHashCode(fromAcct); int toHash = System.identityHashCode(toAcct); if(fromHash<toHash){ synchronized (fromAcct){ synchronized (toAcct){ new Helper().transfer(); } } }else if(fromHash>toHash) { synchronized (toAcct) { synchronized (fromAcct) { new Helper().transfer(); } } }else{ synchronized (tieLock){ synchronized (fromAcct){ synchronized (toAcct){ new Helper().transfer(); } } } } }
以下来坑了,书上说如下代码典型情况下会发生死锁
public class IdentityHashCodeDemo { private static final int NUM_THREADS=20; private static final int NUM_ACCOUNTS=5; private static final int NUM_ITERATIONS=100000; /** * 模拟十万次转账居然会发生死锁这是为什么? * @param args */ public static void main(String[] args) { final Random rnd=new Random(); final Account[] accounts=new Account[NUM_ACCOUNTS]; for (int i=0;i<accounts.length;i++) accounts[i]=new Account(); //模拟十万次转账,不考虑账户为负数的情况 class TransferThread extends Thread{ @Override public void run() { for(int i=0;i<NUM_ITERATIONS;i++){ int fromAcct=rnd.nextInt(NUM_ACCOUNTS); int toAcct=rnd.nextInt(NUM_ACCOUNTS); DollarAmout amout=new DollarAmout(rnd.nextInt(1000)); try { //很纳闷明明用了顺序锁为什么还会很快出现死锁 transferMoney(accounts[fromAcct],accounts[toAcct],amout); } catch (InsufficientResourcesException e) { e.printStackTrace(); } } } } for (int i=0;i<NUM_THREADS;i++) new TransferThread().start(); }}
百思不得其解,最后没办法上网把源码当下来了,查看源码傻眼了,源码如是写着
package net.jcip.examples;import java.util.*;import net.jcip.examples.DynamicOrderDeadlock.Account;import net.jcip.examples.DynamicOrderDeadlock.DollarAmount;/** * DemonstrateDeadlock * <p/> * Driver loop that induces deadlock under typical conditions * * @author Brian Goetz and Tim Peierls */public class DemonstrateDeadlock { private static final int NUM_THREADS = 20; private static final int NUM_ACCOUNTS = 5; private static final int NUM_ITERATIONS = 1000000; public static void main(String[] args) { final Random rnd = new Random(); final Account[] accounts = new Account[NUM_ACCOUNTS]; for (int i = 0; i < accounts.length; i++) accounts[i] = new Account(); class TransferThread extends Thread { public void run() { for (int i = 0; i < NUM_ITERATIONS; i++) { int fromAcct = rnd.nextInt(NUM_ACCOUNTS); int toAcct = rnd.nextInt(NUM_ACCOUNTS); DollarAmount amount = new DollarAmount(rnd.nextInt(1000)); try { DynamicOrderDeadlock.transferMoney(accounts[fromAcct], accounts[toAcct], amount); } catch (DynamicOrderDeadlock.InsufficientFundsException ignored) { } } } } for (int i = 0; i < NUM_THREADS; i++) new TransferThread().start(); }}看到了什么?担心你们粗心我给勾出来了
简直就苦笑不得,书上压根就没有提到这个类,他就默默的用了也不说,然后我们再来看看DynamicOrderDeadlock类
package net.jcip.examples;import java.util.concurrent.atomic.*;/** * DynamicOrderDeadlock * <p/> * Dynamic lock-ordering deadlock * * @author Brian Goetz and Tim Peierls */public class DynamicOrderDeadlock { // Warning: deadlock-prone! public static void transferMoney(Account fromAccount, Account toAccount, DollarAmount amount) throws InsufficientFundsException { synchronized (fromAccount) { synchronized (toAccount) { if (fromAccount.getBalance().compareTo(amount) < 0) throw new InsufficientFundsException(); else { fromAccount.debit(amount); toAccount.credit(amount); } } } } static class DollarAmount implements Comparable<DollarAmount> { // Needs implementation public DollarAmount(int amount) { } public DollarAmount add(DollarAmount d) { return null; } public DollarAmount subtract(DollarAmount d) { return null; } public int compareTo(DollarAmount dollarAmount) { return 0; } } static class Account { private DollarAmount balance; private final int acctNo; private static final AtomicInteger sequence = new AtomicInteger(); public Account() { acctNo = sequence.incrementAndGet(); } void debit(DollarAmount d) { balance = balance.subtract(d); } void credit(DollarAmount d) { balance = balance.add(d); } DollarAmount getBalance() { return balance; } int getAcctNo() { return acctNo; } } static class InsufficientFundsException extends Exception { }}
是不是看完就很好理解为什么在大多数系统下会很快发生死锁了?好坑好坑好坑,一声不说就直接用了个错误的类,以上也说明在附有源码的时候,看书一定要对照源码看,这样能避免很多迷惑性的问题,写此博客也希望能帮到很多跟我一样有困惑的人【我百度,谷歌了很久始终没有找到有人写过这个】
阅读全文
1 0
- 并发编程实战死锁读书笔记之吐槽
- Java并发编程实战--死锁
- 《java并发编程实战》读书笔记——避免死锁的发生
- 《Java并发编程实战》读书笔记四:活跃性和性能,死锁和显示锁
- 《Java并发编程实战》读书笔记四:活跃性和性能,死锁和显示锁
- 《Java并发编程实战》读书笔记
- 《Java并发编程实战》读书笔记
- java并发编程实战-读书笔记
- 《Java并发编程实战》读书笔记
- 《java并发编程实战》读书笔记
- 《Java并发编程实战》读书笔记
- 读书笔记-《Java并发编程实战》
- java并发编程实战读书笔记
- java并发编程实战读书笔记
- Java并发编程实战读书笔记
- java并发编程实战笔记-死锁
- Java 并发编程之死锁
- 并发编程之避免死锁
- Java数组-二分查找原理
- mysql 优化实战
- linux 内核信号量 用户态信号量 详解
- utf-8 去掉中文标点符号
- 滑块运动 — 到目标位置宽度缓慢展开
- 并发编程实战死锁读书笔记之吐槽
- 【学习笔记】天嵌2440第三季下学期——linux tcp网络编程
- Linux中三种网络模式是什么意思——bridged(一桥接模式)
- echarts 地图区域无法显示
- CSS visibility占位隐藏属性
- Mybatis Generator最完整配置详解
- swift_038(Swift之guard关键字(守护))
- ios之Autolayout的运用
- Makefile详解(一)