ReentrantLock 解锁注意事项

学习笔记,欢迎指点: 

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()方法来避免此类错误发生,判断为当前线程持有锁再进行解锁。

根据业务需要,看看是否需要先判断当前线程是否获得锁,避免多层锁导致位置异常,主要保证在进入业务代码块时锁的判断,避免资源浪费和不必要的开销。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值