Locke 接口: 支持予以不同(重入,公平等)的锁规则: 1. 公平锁 2.非公平锁 3.可重入锁
实现lock接口的锁,其构造方法中有 boolean fair参数控制,当fair为
true时,是公平锁,反之为非公平锁。默认是非公平锁。以ReentrantLock为例源码如下:
无参构造:
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
有参构造:
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
对于锁里面一定会有一个FIFO的同步队列进行锁定控制。(非公平锁和公平锁),其
源码如下:公平;FairSync(), NonfairSync()
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
读写锁 : 和lock类似的方式定义了一些读者可以共享而写入者独占的锁。
同步对列提供了两类锁机制: 1. 独占锁 2. 共享锁。 ReadWriteLock中的readLock()和writeLock()分别是共享锁和独占锁。
无障碍锁:StampedLock(加强版的读写锁),读锁和写锁是完全互斥的。也就是说在进行数据输入的时候,读取操作需要进行等待,
等待写锁释放之后才可以继续进行读锁相应的处理。
StampedLock提供了两类锁:1.悲观锁 :会假设互斥锁的装填一直都会存在,默认的处理形式都是悲观锁。
2.乐观锁 :假设在读取的时候没有这么多的写入操作,如果真的发生了写入,那么就需要进行一个状态
判断,通过状态的结果来巨鼎是否需要进行锁的处理。
主要方法:1. 获取读悲观锁,同时获取一个标记 :public long readLock();
2. 获取读悲观锁,同时获取一个标记 :public long writeLock();
3. 获取读的乐观锁: public 龙tryOptimisticRead();
4. 进行指定标记的验证 :public boolean validate (long stamp);
5. 释放锁 :public void unlick(long stamp);
6. 释放读锁 :public void unlickRead(long stamp);
7. 释放写锁 :public void unlickWrite(long stamp);
互斥锁:ReentrantLock :普通可重用的互斥锁进行操作。lock 于ReentranLock 实现的只是一个最为基础的锁的处理机制,利用Lock ()
与unlock()方法就可以构建出一个类似同步代码块的机构。但是其结构要比通过代码块更加简单。
扩展: 可重入锁
1.synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,
且次数需一样,否则其他线程无法获得锁。
2.synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,
不易操作,但非常灵活。
3.synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。
ReentrantLock好像比synchronized关键字没好太多,我们再去看看synchronized所没有的,一个最主要的就是ReentrantLock还可以实现
公平锁机制。
!!ReentrantLock的可重入体现
final boolean nonfairTryAcquire(int acquires) { //ReentrantLock模式使用的是非公平锁,这样能提高系统的响应性能
final Thread current = Thread.currentThread();
int c = getState(); //获取资源的状态,
if (c == 0) { //为0就是别人还没有获取到锁,这个时候当前线程就可以获取到锁
if (compareAndSetState(0, acquires)) { //用cas的方式获取到锁
setExclusiveOwnerThread(current); //这个方法里面就只有这一句 exclusiveOwnerThread = thread; 设置当前线程是独占线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //重点来了,这个方法就是主要判断是不是可重入的,如果之前的判断资源的状态是被上锁了,就会执行到这里,如果判断是本线程
int nextc = c + acquires; //把资源的的请求次数加1
if (nextc < 0) // 当然也不是可以不限加的,如果超出的int的范围,抛出一个error的错误
throw new Error("Maximum lock count exceeded");
setState(nextc); //设置资源状态
return true;
}
return false;
}
总结:ReentrantLock可重入主要体现在current == getExclusiveOwnerThread()这个判断方法上面。如果是当前重入线程,资源状态添加
请求数,注意释放的时候也是要释放这个多次的。