并发编程之ReentrantLock

简介

在java中,实现锁有2种方式,一个是synchronized,一个是Lock,今天我们讲讲可重入锁ReentrantLock,ReentrantLock相对于传统的synchronized,优势在于提供了更加灵活的方式使用锁,比如可重入,锁超时,锁中断,公平、非公平锁。

ReentrantLock是基于AQS独占锁实现的, 阅读本文之前还需要了解几个概念:

  • 可重入锁:指的是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码。也就是同一线程可以获得多个锁。不然就会发生死锁问题。
  • 可中断锁:在某些条件下可以相应中断的锁。在Java中,synchronized就不是可中断锁,而 Lock是可中断锁。
  • 公平锁:公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。
  • 非公平锁:无法保证锁的获取是按照请求锁的顺序进行的。有可能锁刚被释放,正好新来了个线程请求锁,这样后面等待的线程就不能获得锁。在极端情况下,可能导致一直无法获取锁。

源码分析

非公平锁
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

         
        final void lock() {
            if (compareAndSetState(0, 1))
               //如果没有线程占用锁资源,直接独占资源,更新AQS类的state,当前线程独占
               setExclusiveOwnerThread(Thread.currentThread()); 
            else
                //AQS类的acquire,调用实现类的tryAcquire
                acquire(1);
        }
        
        /**
         * 获取非公平锁
         * 1. 当前无锁,给当前线程上锁
         * 2. 当前有锁,但是加锁的线程是当前线程,增加状态值
         * 其他情况返回false
         */
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
        //非公平尝试获取锁
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //如果资源没被任何线程占有过
                if (compareAndSetState(0, acquires)) {
                    //cas成功,设置当前线程独占
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {    
                //当前线程重入,state + 1
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            //添加到等待队列,等待通知
            return false;
        }

公平锁

公平锁和非公平锁的区别在于hasQueuedPredecessors(),它用来返回队列中是否有比当前线程等待更久的线程

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        /**
         * 获取公平锁
         * 1. 当前无锁,并且没有等待更久的线程的话,给当前线程上锁
         * 2. 当前有锁,但是加锁的线程是当前线程,增加状态值
         * 其他情况返回false
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

转载于:https://my.oschina.net/xiongying0214/blog/1976004

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值