package cn.study.concurrency.ch10;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.naming.InsufficientResourcesException;
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
{
class
Helper
{
public
void transfer() throws InsufficientResourcesException
{
if
(fromAccount.getBalance() < amount)
{
throw
new
InsufficientResourcesException();
}
else
{
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
int fromHash = System.identityHashCode(fromAccount);
int toHash = System.identityHashCode(toAccount);
if
(fromHash < toHash)
{
synchronized(fromAccount)
{
synchronized(toAccount)
{
new
Helper().transfer();
}
}
}
else
if
(toHash < fromHash)
{
synchronized(toAccount)
{
synchronized(fromAccount)
{
new
Helper().transfer();
}
}
}
else
{
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 {
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();
}
}