先了解一下Java.util.concurrent.locks.Lock接口的实现类:ReentrantLock与ReentrantReadWriteLock的内部类中的ReadLock与WriteLock;分别叫重入锁,读入锁,写入锁。lock必须被显式地创建、锁定和释放,为了可以使用更多的功能,一般用ReentrantLock为其实例化。为了保证锁最终一定会被释放(可能会有异常发生),要把互斥区放在try语句块内,并在finally语句块中释放锁,尤其当有return语句时,return语句必须放在try字句中,以确保unlock()不会过早发生,从而将数据暴露给第二个任务。因此,采用lock加锁和释放锁的一般形式如下:
@Override
public void autoMatch(String loanAgreementId, String currentUserId) {
//加锁 lock效率高
Lock lock = new ReentrantLock();
lock.lock();
try {
AgreementDomain agreementdomain = agreementService.getPrimaryKeyObj(loanAgreementId);
ProductDomain product = productService.getPrimaryKeyObj(agreementdomain.getProductId());
Double actualamount = agreementdomain.getTotalPayment();
Double serviceCharge = 0d;
// 检查是否收取服务费
if (1 == product.getServiceCharge())
serviceCharge = 500D;
String uuid = "";
// 获取排序后的资金池
List<PartnerAmountModel> pool = weightCalculation();
if (pool == null || pool.size() == 0) {
lending4SeatsBoss(agreementdomain, actualamount, serviceCharge, currentUserId);
} else {
for (PartnerAmountModel partneramountmodel : pool) {
if (actualamount.compareTo(partneramountmodel.getPartnerRemainingAmount()) < 0)
uuid = partneramountmodel.getId();
break;
}
if (StringUtils.isNotBlank(uuid) == true) {
partnerLendingMapper.insert(partnerlending);
agreement.setUpdateTime(new Date());
agreement.setUpdaterId(currentUserId);
agreementService.update(agreement);
}
}
} finally {
lock.unlock(); // 锁必须在finally块中释放
}
}
ReetrantLock有两种锁:忽略中断锁和响应中断锁。忽略中断锁与synchronized实现的互斥锁一样,不能响应中断,而响应中断锁可以响应中断。
如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,如果此时ReetrantLock提供的是忽略中断锁,则它不会去理会该中断,而是让线程B继续等待,而如果此时ReetrantLock提供的是响应中断锁,那么它便会处理中断,让线程B放弃等待,转而去处理其他事情。
读写锁
另外,synchronized获取的互斥锁不仅互斥读写操作、写写操作,还互斥读读操作,而读读操作时不会带来数据竞争的,因此对对读读操作也互斥的话,会降低性能。Java5中提供了读写锁,它将读锁和写锁分离,使得读读操作不互斥,获取读锁和写锁的一般形式如下:
ReadWriteLock rl= new ReentrantReadWriteLock();
//获取写锁
rl.writeLock().lock() ;
//获取读锁
rl.readLock().lock() ;