ReentrantLock

java并发编程之美 学习笔记

独占锁 ReentrantLock

结构

public class ReentrantLock implements Lock, java.io.Serializable {
 	private final Sync sync;
 	
 	//Sync 类直接继承自 AQS ,
	abstract static class Sync extends AbstractQueuedSynchronizer {
	}
	
	//非公平锁
	static final class NonfairSync extends Sync {
	}
	
	//公平锁
	static final class FairSync extends Sync {
	}
	
	public ReentrantLock() {
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
}

在这里,AQS中的state表示线程获取锁的可重入次数.

  • state == 0 ,表示当前锁没有被任何线程持有
  • 当一个线程第一次获取锁时,会使用CAS设置state为1,当CAS操作成功时,记录该锁的持有者为当前线程。
  • 在该线程获取锁并没有释放的情况下,第二次获取锁后,state状态值+1,在线程释放锁时state值-1,当state值再次为0时,表示当前线程释放锁.

获取锁

  public void lock() {
  	//委托给sync,根据构造函数选择:公平or非公平锁
      sync.lock();
  }

非公平锁


//java.util.concurrent.locks.ReentrantLock.NonfairSync
static final class NonfairSync extends Sync {
	final void lock() {
		//cas操作尝试设置state == 1
	    if (compareAndSetState(0, 1))
	    	//如果cas操作成功,设置lock当前持有者 为当前线程
	        setExclusiveOwnerThread(Thread.currentThread());
	    else
	    	//1.调用AQS的acquire方法
	        acquire(1);
	}


	//2.
	protected final boolean tryAcquire(int acquires) {
		//3. 由父类Sync实现
	    return nonfairTryAcquire(acquires);
	}
}

//java.util.concurrent.locks.AbstractQueuedSynchronizer
//1
 public final void acquire(int arg) {
 	//2.尝试获取锁--由子类实现
    if (!tryAcquire(arg) &&
    	//如果尝试获取失败,则将当前线程加入阻塞队列
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}


//java.util.concurrent.locks.ReentrantLock.Sync
//3.
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
    	//c == 0 ,表示当前锁为空闲状态
        if (compareAndSetState(0, acquires)) {
        	//设置当前线程为锁的持有者
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // c != 0 ,但锁的持有者为当前线程
    else if (current == getExclusiveOwnerThread()) {
    	//计算并更新 state
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }

    //否则返回false
    return false;
}

公平锁

//java.util.concurrent.locks.ReentrantLock.fairSync
static final class FairSync extends Sync {
    final void lock() {
    	//aqs内部调用tryAcquire
        acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
        	/**
        	 * hasQueuedPredecessors(): aqs等待队列中head.next 指定的node持有的线程是否为当前线程
        	 * 即当前线程锁持有node,是否为第一个等待队列中第一个node(除去head的第一个)
        	 * 如果是第一个,返回false, 进行2
        	 * 如果不是,返回true,跳出逻辑, 整个方法 返回false,即获取失败
        	 */
            if (!hasQueuedPredecessors() && //1
                compareAndSetState(0, acquires)) {//2 cas设置state
            	 //设置当前线程为锁的持有者
                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;
    }
}


//java.util.concurrent.locks.AbstractQueuedSynchronizer
public final boolean hasQueuedPredecessors() {
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    //h.next 表示head指向的第一个元素, 判断它持有的线程是否为当前线程
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

公平与非公平

  • 公平锁: 它是按照线程在aqs等待队列中的时间先后顺序来依次获取锁的。
  • 非公平锁: 它是抢夺策略来获取锁的,如下图:在这里插入图片描述

释放锁

  • 如果当前线程持有该锁 ,则更新AQS的state-1,如果减去1后当前状态值为 0,则当前线程会释放该锁,否则线程依然持有锁。
  • 如果未持有锁的线程,执行释放锁的操作,则抛出异常IllegalMonitorStateException
//java.util.concurrent.locks.ReentrantLock
  public void unlock() {
  	//1.委托sync执行释放操作,该方法由AQS实现;
      sync.release();
  }
  
//java.util.concurrent.locks.AbstractQueuedSynchronizer
 public final boolean release(int arg) {
	//2. tryRelease由子类Sync实现
     if (tryRelease(arg)) {
          Node h = head;
          if (h != null && h.waitStatus != 0)
          	//3. 从等待队列head头部开始寻找第一个不为空的node
          	//调用LockSupport.unpark()唤醒之。
             unparkSuccessor(h);
          return true;
      }
      return false;
  }

//java.util.concurrent.locks.AbstractQueuedSynchronizer.Sync
//3
protected final boolean tryRelease(int releases) {
     int c = getState() - releases;
      if (Thread.currentThread() != getExclusiveOwnerThread())
      	//如果当前线程不是锁的持有线程,直接抛出异常
          throw new IllegalMonitorStateException();
      boolean free = false;
      if (c == 0) {
          free = true;
          //当执行递减操作后,state == 0 ,释放锁,更新持有锁线程为null; 
          //free = true
          setExclusiveOwnerThread(null);
      }
      //如果state != 0 ,仅执行更新,并不释放锁;   free = false
      setState(c);
      return free;
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值