文章目录
ReentrantLock公平与非公平锁如何实现
公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取锁就会失败,并且会加入阻塞队列。
非公平锁获取锁时不会判断阻塞队列是否有线程再等待,所以对于已经在等待的线程来说是不公平的,但如果是因为其它原因没有竞争到锁,它也会加入阻塞队列。
进入阻塞队列的线程,竞争锁时都是公平的,应为队列为先进先出(FIFO)。
源码分析
构造函数
构造方法的源码
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();//其中两个为内置类
}
ReentrantLock内置类
abstract static class Sync extends AbstractQueuedSynchronizer
static final class NonfairSync extends Sync //不公平
static final class FairSync extends Sync //公平
通过构造函数与三个内置类,我们就能知道ReentrantLock是怎么实现“公平锁”与“非公平锁“的
sync对象
ReentrantLock中的方法实现机会全部都是通过sync对象实现的
private final Sync sync;
ReentrantLock的普通方法
ReentrantLock的普通方法源码
public void unlock() {
sync.release(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void lock() {
sync.lock();
}
我就不一一列举了,都是通过Sync对象实现的。
NonfairSync
非公平锁的流程
lock()
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
acquire()
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire()
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
nonfairTryAcquire()
不公平的竞争锁方式,不会去礼让阻塞队列里的线程。
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;
}
FairSync
公平锁实现的流程图
lock()
调用acquire()获取锁
final void lock() {
acquire(1);
}
acquire()
获取锁
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
acquireQueued()AQS中方法
将线程加入阻塞队列中
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
tryAcquire()
尝试获取锁。成功返回true失败返回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;
}
编程实现公平锁与非公平锁
package club.yzren.Lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class RL implements Runnable{
int anInt;
RL(int anInt){
this.anInt=anInt;
}
@Override
public void run(){
NonfairLock2.fair(anInt);
// NonfairLock2.unfair(anInt); //通过修改注释来运行公平与非公平的锁
}
}
public class NonfairLock2 {
public static Lock unfairlock=new ReentrantLock(false);
public static Lock fairlock=new ReentrantLock(true);
public static void fair(int i){
System.out.print(i+"尝试获取锁");
fairlock.lock();
System.out.print("\n"+i+" 获取锁成功");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("\n"+i+"释放锁");
fairlock.unlock();
}
public static void unfair(int i){
System.out.print(i+"尝试获取锁");
unfairlock.lock();
System.out.print("\n"+i+" 获取锁成功");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("\n"+i+"释放锁");
unfairlock.unlock();
}
public static void main(String[] args) throws InterruptedException {
int i=0;
Thread[] thread=new Thread[1024];
for(i=0;i<1024;i++)
thread[i]=new Thread(new RL(i));
for(i=0;i<1024;i++) {
thread[i].start();
}
}
}
公平锁运行结果图
可以发现在0释放锁之后,有线程在争夺锁,但是当先争夺锁的线程会礼让阻塞队列里的线程,所以阻塞队列先获得锁。
非公平锁运行截图
o释放锁后,但是当先争夺锁的线程不会礼让阻塞队列里的线程,两者一起竞争锁。