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()这个判断方法上面。如果是当前重入线程,资源状态添加 请求数,注意释放的时候也是要释放这个多次的。