什么时候使用Reentrant锁?
Java 5.0提供Reentrant Lock. 相比‘synchronized’ 和 ‘volatile’,能更好完成并发
之前我们使用下面代码:
public synchronized void doAtomicTransfer(){
//enter synchronized block , acquire lock over this object.
operation1()
operation2();
} // exiting synchronized block, release lock over this object.
使用同步锁容易引起死锁。以下面transferMoneyWithSync转账为案例为例子:
public void transferMoneyWithSync(Account fromAccount, Account toAccount,
float amount) throws InsufficientAmountException {
synchronized (fromAccount) {
// acquired lock on fromAccount Object
synchronized (toAccount) {
// acquired lock on toAccount Object
if (amount > fromAccount.getCurrentAmount()) {
throw new InsufficientAmountException(
"Insufficient Balance");
} else {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
}
当出现:
A: transferMoney(acc1, acc2, 20);
B: transferMoney(acc2, acc1 ,25);
两个线程陷入互相等待的死锁当中。
ReentrantLock有下面几个方法:
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
.....
使用tryLock能够加入时间日期后能够避免这种死锁等待,这种方法被称为"定时查询锁收购"。它可以让你重新获得控制权,如果你不能获得必需的锁,释放你现在已经获得锁,然后重试。
下面使用一个有时间的锁:
public boolean transferMoneyWithTryLock(Account fromAccount,
Account toAccount, float amount) throws InsufficientAmountException, InterruptedException {
// we are defining a stopTime
long stopTime = System.nanoTime() + 5000;
while (true) {
if (fromAccount.lock.tryLock()) {
try {
if (toAccount.lock.tryLock()) {
try {
if (amount > fromAccount.getCurrentAmount()) {
throw new InsufficientAmountException(
"Insufficient Balance");
} else {
fromAccount.debit(amount);
toAccount.credit(amount);
}
} finally {
toAccount.lock.unlock();
}
}
} finally {
fromAccount.lock.unlock();
}
}
if(System.nanoTime() < stopTime)
return false;
Thread.sleep(100);
}//while
}
如果锁时间过5000ms没有释放,将返回出错。如果锁在指定时间不能被得到,transferMoney方法将返回一个失败通知,并退出。
中断锁收购
lockInterruptibly的方法:收购中断锁允许锁在被撤销活动中再次使用。
假设我们共享Line发送消息,如果另一个线程来中断当前线程应当释放锁,并执行退出或关闭操作来取消当前任务。
public boolean sendOnSharedLine(String message) throws InterruptedException{
lock.lockInterruptibly();
try{
return cancellableSendOnSharedLine(message);
} finally {
lock.unlock();
}
}
private boolean cancellableSendOnSharedLine(String message){