问题:在解锁的最后一步调用了LockSupport.unpark()来解锁,
而一个线程B进入同步等待队列阻塞的时候根据先去接点的waitState==-1来判断是否需要阻塞,
那么在他判断完前驱节点线程A waitState==-1成立然后发生系统调度,执行其他线程,
而这时候线程A获取锁并解锁调用了LockSupport.unpark(),然后执行线程B,
线程B会执行阻塞的过程,线程B会被阻塞掉,然后后面的节点都不能获取锁么?
除了公平的加锁方式,可重入锁还提供了非公平模式(默认)的加锁。在非公平模式下只要锁还没有被其他线程获取,就有机会成功获取锁,
当然已加入到队列中的线程还是要按照顺序排队获取。这样做会减少需要阻塞、唤醒的线程,降低由于阻塞、唤醒带来的额外开销,
但是在队列中等待的线程可能会被活活饿死(很惨的那种,出了问题排查的时候)
加锁入口同公平模式:
public void lock() { //都是调用到同步器的lock方法 sync.lock(); }lock()直接调用同步器实现的lock()
/** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { //在这里不管是否有线程在排队,直接尝试加锁 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else //加锁失败则调用AQS的acquire方法 acquire(1); }acquire()方法在AQS中实现,和公平锁的一致,方便阅读就再写一次
具体解释见注释
//以独占的方法加锁,并且忽略中断 //那是不是还有响应中断的加锁呢?? public final void acquire(int arg) { //先尝试调用同步器的tryAcquire()方法加锁 if (!tryAcquire(arg) && //加锁失败的情况下将当前线程放入同步等待队列中 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //acquireQueued返回值是线程在等待期间是否被中断,如果有则还原中断现场 selfInterrupt(); }同步器的tryAcquire()方法见非公平模式的同步器,会调用到Sync的nonfairTryAcquire()方法,
如果加锁失败则会依次构建同步等待队列->尝试加锁->失败则判断是否需要进行阻塞->是则阻塞等待前驱节点唤醒->尝试加锁这样的流程
这个流程同公平锁
//默认提供了非公平机制的加锁过程 //acquires 申请加锁的次数,一般情况下是一次,但是有多次的情况,在Condition中会看到 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); //获取锁的状态,getState在AQS中实现 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; } 非公平锁的解锁非公平锁的解锁过程同公平锁,释放过程不存在公平于非公平,具体逻辑全部由Sync和AQS实现;
公平锁和非公平锁的加锁流程图