ReentrantLock和ReentrantReadWiteLock

ReentrantLock

可重入锁:内建锁隐式支持可重入锁,通过自增获取,自减释放的方式来实现可重入。

特点:1)线程获取锁的时候,如果当前线程已经持有锁,直接尝试再次获取

2)由于锁可以被获取N次,所以释放的时候要释放N次之后才能算是真正的释放成功。

源码及分析:

final boolean nonfairTryAcquire(int acquires) {
            //
拿到当前线程
           
final Thread current = Thread.currentThread();
            //
获取当前同步状态
           
int c = getState();
            if (c == 0) {
            //
当前线程还没有被获取,当前线程尝试CAS获取同步状态
               
if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //
此时同步状态不为0,表示已有线程获取到了同步状态;判断持有线程是否为当前线程
           
else if (current == getExclusiveOwnerThread()) {
            //
若是当前线程,同步状态再次加一(可重入特性的实现)和monitor机制一样
               
int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                    //
将再次加一后的状态写回内存
               
setState(nextc);
                return true;
            }
            return false;
        }

 

公平锁和非公平锁:

公平锁(FairLock):锁的获取满足时间上的绝对顺序(请求资源上的绝对顺序)来获取锁,也就是说等待的时间越长越容易获取到锁,等待时间最长的线程一定最先获取到锁。

非公平锁(NonFairLock):锁的获取不一定满足时间上的绝对顺序。Lock方法先进行CAS,不再队列中的线程可能先获取到锁。

二者的区别:tryAcquire方法不同,都是先获取线程状态,公平锁增加了!hasQueuedPredecessors进行判断,当同步队列中存在非空节点,就将这个线程直接封装为Node进入队列进行排队。举个例子:A线程是持有锁线程,B、C、D在队列中处于阻塞,A线程通过unLock方法释放锁release方法唤醒B线程,不在队列中的E、F也要竞争锁,那么这个时候B、E、F三个线程同时竞争这把锁,非公平锁就会让这三个线程进行CAS操作来获取lock;公平锁就不会进行CAS操作,而是让B线程拿到锁,将E、F线程包装为节点尾插入队列,排队等待获取锁。公平锁需要频繁的进行切换,唤醒与阻塞;非公平锁不需要频繁切换,降低了性能的开销,但是有可能会导致部分线程一直无法获取到Lock造成线程饥饿现象。一般没有特定的公平性要求尽量选择非公平锁。

 

ReentrantLock采用的是非公平锁机制,因为非公平锁的吞吐量大,效率高,速度快。

 

ReentrantReadWriteLock:可重入读写锁。

先来说说读写者模型,读写锁运行同一时刻可以被多个读线程访问,但是一旦被写线程访问,所有的线程均不能访问,所有的读线程和其他写线程都会被阻塞。所以我们可以看出来读锁是一个共享锁,而写锁是一个独占锁。

ReentrantReadWriteLock写锁的获取也是tryAcquire方法,比ReentrantLock多了一些判断:1.读锁不为0或写锁不为0一定失败,因为写锁是独占锁。2.如果读锁超过了饱和值,那么也一定失败。

获取读锁状态用getState方法,返回值是int;获取写锁状态使用exclusiveCount返回值也是int;State是32位同步状态int型的变量,高十六位表示读线程获取的次数,低十六位是写线程获取的次数。释放:同步状态减去写状态,判断当前状态是否为0,为0就释放写锁,不为0就更新同步状态。

ReentrantReadWriteLock读锁的获取是tryAcquireShared,返回值为获取次数。共享锁如果单独作为一个锁来使用并没有什么意义,一般都是和写锁结合使用来实现读写者模型。

只要当前写线程没有获取锁,并且读线程没有到达最大值就可以获取成功。

释放:同步状态减去读状态,为0就返回true

读写锁的应用场景:缓存【内存就是最大的一个缓存,缓存实际上就是Map】的实现。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值