【JAVA并发编程实战】8、锁顺序死锁
package cn.study.concurrency.ch10;
public class Account {
private String staffAccount; //账号
private String passWord; //密码
private int balance; //账户余额
public Account(int money) {
this.balance = money;
}
public String getStaffAccount() {
return staffAccount;
}
public void setStaffAccount(String staffAccount) {
this.staffAccount = staffAccount;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public void debit(int amount)
{
System.out.println("转出账户:" + amount);
}
public void credit(int amount)
{
System.out.println("转入账户:" + amount);
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
package cn.study.concurrency.ch10; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import javax.naming.InsufficientResourcesException; /**
* 通过制定确定的锁顺序来避免死锁
* @author xiaof
*
*/
public class DeathLock {
public void transferMoney(Account fromAccount, Account toAccount, int amount) throws InsufficientResourcesException
{
synchronized(fromAccount)
{
synchronized(toAccount)
{
//按参数的顺序上锁,这个依据参数的调用方法的顺序
if(fromAccount.getBalance() < amount)
{
//账户余额不足,无法转账
throw new InsufficientResourcesException();
}
else
{
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
}
/**
* 这个用来在无法判定枷锁顺序的时候的加时赛锁
*/
private static final Object tieLock = new Object(); public static void transferMoney2(final Account fromAccount, final Account toAccount, final int amount) throws InsufficientResourcesException
{
/**
* 辅助内部类
* @author xiaof
*
*/
class Helper
{
public void transfer() throws InsufficientResourcesException
{
//内部类可以随意访问外部类成员
//按参数的顺序上锁,这个依据参数的调用方法的顺序
if(fromAccount.getBalance() < amount)
{
//账户余额不足,无法转账
throw new InsufficientResourcesException();
}
else
{
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
//返回给定对象的哈希码,该代码与默认的方法 hashCode() 返回的代码一样,无论给定对象的类是否重写 hashCode()
int fromHash = System.identityHashCode(fromAccount);
int toHash = System.identityHashCode(toAccount);
//根据hash值判定加锁顺序,那么一样的对象的锁顺序就一定一样
if(fromHash < toHash)
{
synchronized(fromAccount)
{
synchronized(toAccount)
{
new Helper().transfer();
}
}
}
else if(toHash < fromHash)
{
synchronized(toAccount)
{
synchronized(fromAccount)
{
new Helper().transfer();
}
}
}
else
{
//如果很不巧,hash值是一样的,那么就需要一个加时赛的机制,先获取外部锁,然后再此基础上对两个对象随机上锁
synchronized(tieLock)
{
synchronized(fromAccount)
{
synchronized(toAccount)
{
new Helper().transfer();
}
}
}
} } static Account account1 = new Account(999);
static Account account2 = new Account(999); public static void main(String[] args) throws InsufficientResourcesException {
//对于第一个方法很容易死锁
//比如:当有两个同时执行这个方法的调用时候
// DeathLock dl = new DeathLock();
//这个时候第一个调用在锁了account1,然后第二个调用锁了account2
//同时第一个需要account2,第二个需要account1,这就发生竞争死锁了
// dl.transferMoney(account1, account2, 998);
// dl.transferMoney(account2, account1, 998);
//
// dl.transferMoney2(account1, account2, 998);
ExecutorService pool = Executors.newFixedThreadPool(10);
for(int i = 0; i < 5; ++ i)
{
pool.execute(new Runnable() {
@Override
public void run() {
try {
DeathLock.transferMoney2(account1, account2, 998);
} catch (InsufficientResourcesException e) {
e.printStackTrace();
}
}
});
} for(int i = 0; i < 5; ++ i)
{
pool.execute(new Runnable() {
@Override
public void run() {
try {
DeathLock.transferMoney2(account2, account1, 998);
} catch (InsufficientResourcesException e) {
e.printStackTrace();
}
}
});
} pool.shutdown();
}
}
测试结果:

【JAVA并发编程实战】8、锁顺序死锁的更多相关文章
- JAVA并发编程学习笔记------锁顺序死锁
一.需求描述: 将资金从一个账户转移到另一个账户. 二.程序实现: (1)账户类: public class Account { private long account; public Accoun ...
- java并发编程实战《五》死锁
一不小心就死锁了,怎么办? 在上一篇文章中,我们用 Account.class 作为互斥锁,来解决银行业务里面的转账问题,虽然这个方案不存在并发问题,但是所有账户的转账操作都是串行的,性能太差. 向现 ...
- Java并发编程实战(4)- 死锁
在这篇文章中,我们主要讨论一下死锁及其解决办法. 目录 概述 死锁案例 死锁的原因和预防 破坏占用且等待条件 破坏不可抢占条件 破坏循环条件 使用等待-通知机制 Java中的等待-通知机制 条件曾经满 ...
- Java并发编程实战 04死锁了怎么办?
Java并发编程文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 前提 在第三篇 ...
- Java并发编程实战 03互斥锁 解决原子性问题
文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...
- 【Java并发编程实战】----- AQS(二):获取锁、释放锁
上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock
ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介
注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的l ...
- Java并发编程实战 05等待-通知机制和活跃性问题
Java并发编程系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 Java并发编程实 ...
- Java并发编程实战——读后感
未完待续. 阅读帮助 本文运用<如何阅读一本书>的学习方法进行学习. P15 表示对于书的第15页. Java并发编程实战简称为并发书或者该书之类的. 熟能生巧,不断地去理解,就像欣赏一部 ...
随机推荐
- 《Entity Framework 6 Recipes》中文翻译系列 (30) ------ 第六章 继承与建模高级应用之多对多关联
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章 继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章 ...
- Web Modify The Html Elements According Url Parameters With Jquery
需求说明 根据URL的参数, 来批量的对某些HTML元素做统一的修改. 解决思路 首先, 想办法获得这个URL的参数, 然后遍历对应的HTML元素, 做出对应的修改. 即可. 代码实现 <!DO ...
- 《Node即学即用》—— 读后总结
导图
- 再谈使用Emit把Datatable转换为对象集合(List<T>)
一.前因和存在的问题 前面我写了一篇<使用Emit把Datatable转换为对象集合(List<T>)>的博文,其实起源于我自己编写的一个orm工具(见前面几篇博文有介绍),里 ...
- Atitit图像处理的用途
Atitit图像处理的用途 1.1. 分类识别 (人脸检测,肤色识别,人类检测:1 1.2. 炫丽的动态按钮生成:色相旋转+自己的草书等图片合成,图片自动裁剪1 1.3. 集成调用自绘gui接口:识别 ...
- 设计模式之里氏代换原则(LSP)
里氏代换原则(Liskov Substitution Principle, LSP) 1 什么是里氏代换原则 里氏代换原则是由麻省理工学院(MIT)计算机科学实验室的Liskov女士,在1987年的O ...
- Linux服务器常用操作
Context 客户端:MacOS Terminal终端 服务器端:Linux v2.6 更新项目 进程 查看:ps -ef | grep * 杀死:kill -9 <pid> 数据库 备 ...
- python进程池:multiprocessing.pool
本文转至http://www.cnblogs.com/kaituorensheng/p/4465768.html,在其基础上进行了一些小小改动. 在利用Python进行系统管理的时候,特别是同时操作多 ...
- Android入门(二十二)解析JSON
原文链接:http://www.orlion.ga/687/ 解析JSON的方式有很多,主要有官方提供的 JSONObject,谷歌的开源库 GSON.另外,一些第三方的开源库如 Jackson.Fa ...
- 深入学习jQuery选择器系列第八篇——过滤选择器之伪子元素选择器
× 目录 [1]通用形式 [2]反向形式 [3]首尾元素 [4]唯一元素 前面的话 本文是子元素选择器的续篇,主要介绍关于nth-of-type()选择器的内容.该部分内容并非没有出现在<锋利的 ...