先了解一下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() ;