【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并发编程实战简称为并发书或者该书之类的. 熟能生巧,不断地去理解,就像欣赏一部 ...
随机推荐
- 如果调用ASP.NET Web API不能发送PUT/DELETE请求怎么办?
理想的RESTful Web API采用面向资源的架构,并使用请求的HTTP方法表示针对目标资源的操作类型.但是理想和现实是有距离的,虽然HTTP协议提供了一系列原生的HTTP方法,但是在具体的网络环 ...
- EF:打开Oracle连接时报错
基础提供程序在 Open 上失败. The underlying provider failed on Open. 解决:安装最新的ODTwithODAC121024.
- Docker实践:安装wordpress
本文将示例如何使用Docker来安装wordpress.使用三种方法: 1.基于官方的wordpress镜像使用docker run实现: 2.基于官方的wordpress镜像使用fig命令编排工具实 ...
- 《Spark快速大数据分析》—— 第七章 在集群上运行Spark
- Base64编码原理分析
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,在了解Base64编码之前,先了解几个基本概念:位.字节. 位:"位(bit)"是计算机中最小的数据单位.每一位 ...
- Java基础-服务器的发送和接收
package hanqi.test; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWri ...
- mysql导入导出sql文件
window下 1.导出整个数据库mysqldump -u 用户名 -p 数据库名 > 导出的文件名mysqldump -u dbuser -p dbname > dbname.sql2. ...
- KNN算法
1.算法讲解 KNN算法是一个最基本.最简单的有监督算法,基本思路就是给定一个样本,先通过距离计算,得到这个样本最近的topK个样本,然后根据这topK个样本的标签,投票决定给定样本的标签: 训练过程 ...
- Neutron 功能概述 - 每天5分钟玩转 OpenStack(65)
从今天开始,我们将学习 OpenStack 的 Networking Service,Neutron.Neutron 的难度会比前面所有模块都大一些,内容也多一些.为了帮助大家更好的掌握 Neutor ...
- 写在最前面 - 每天5分钟玩转 OpenStack(1)
<每天5分钟玩转 OpenStack>是一个 OpenStack 教程,这是第 1 篇. 这个教程有下面两个特点: 系统讲解 OpenStack 从架构到各个组件:从整体到细节逐一讨论 重 ...