学习笔记,欢迎指点:
ReentrantLock相比于synchronized,有更强大有丰富的功能扩展,单机项目推荐使用,这里不多做介绍,下面说一下我在项目中遇到的一种问题:正常逻辑下,
public class TestThread implements Runnable{
private static ReentrantLock rLock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
TestThread imp = new TestThread();
for(int i=0;i<2;i++){
new Thread(imp).start();
Thread.sleep(200);
}
// System.exit(0);
}
public void run() {
try {
if(rLock.tryLock()){
//休眠5秒 用于第二次请求 抛出异常
System.out.println("当前【持有锁】的线程编号:"+Thread.currentThread().getId());
Thread.sleep(1000);
}else {
System.out.println("当前资源已被锁定!【"+Thread.currentThread().getId()+"】线程号被踢出!");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
System.out.println("线程:【"+Thread.currentThread().getId()+"】,开始解锁");
rLock.unlock();
System.out.println("线程:【"+Thread.currentThread().getId()+"】,解锁完成!");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
}
}
运行结果
当前【持有锁】的线程编号:10
当前资源已被锁定!【11】线程号被踢出!
线程:【11】,开始解锁
java.lang.IllegalMonitorStateException
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
at testThread.TestThread.run(TestThread.java:32)
at java.lang.Thread.run(Unknown Source)
线程:【10】,开始解锁
线程:【10】,解锁完成!
结果是线程11去解锁线程10的锁,抛出了异常。如果此处运用事务,就会造成不必要资源浪费和线程开销。所以此处加锁尽量不要直接使用tryLock方法,看一下tryLock内部实现:
public boolean tryLock() {
return sync.nonfairTryAcquire(1);//默认给的值就是1:锁定
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();//获取当前锁的状态
if (c == 0) {
if (compareAndSetState(0, acquires)) {//设置锁状态
setExclusiveOwnerThread(current);//标记当前获得锁的线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) {//已被当前线程锁定
int nextc = c + acquires;//叠加状态数
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
简单的处理一下获得锁方法:
public boolean tryLock(ReentrantLock lock,String opName,String opFlag) {
try {
if(lock.tryLock()){
logger.info("【"+opName+"-锁定】:" + opFlag);
return true;
}
return false;
} catch (Exception e) {
logger.info("操作标识:"+opFlag+"------"+opName+"锁定异常!",e);
return false;
}
}
非必要时可以使用isHeldByCurrentThread()方法来避免此类错误发生,判断为当前线程持有锁再进行解锁。
根据业务需要,看看是否需要先判断当前线程是否获得锁,避免多层锁导致位置异常,主要保证在进入业务代码块时锁的判断,避免资源浪费和不必要的开销。