当前位置:   article > 正文

AQS中那些waitStatus(一)_aqs waitstatus

aqs waitstatus

系列文章目录

ReentrantLock初认知
AQS中可重入锁ReentrantLock源码一加锁过程
AQS中可重入锁ReentrantLock源码一释放锁过程
AQS中那些waitStatus(一)
AQS中那些waitStatus(二)


waitStatus有哪些

// CANCELLED:由于超时或中断,此节点被取消。节点一旦被取消了就不会再改变状态。特别是,取消节点的线程不会再阻塞。
static final int CANCELLED =  1;
// SIGNAL:此节点后面的节点已(或即将)被阻止(通过park),因此当前节点在释放或取消时必须断开后面的节点
// 为了避免竞争,acquire方法时前面的节点必须是SIGNAL状态,然后重试原子acquire,然后在失败时阻塞。
static final int SIGNAL    = -1;
// 此节点当前在条件队列中。标记为CONDITION的节点会被移动到一个特殊的条件等待队列(此时状态将设置为0),直到条件时才会被重新移动到同步等待队列 。(此处使用此值与字段的其他用途无关,但简化了机制。)
static final int CONDITION = -2;
//传播:应将releaseShared传播到其他节点。这是在doReleaseShared中设置的(仅适用于头部节点),以确保传播继续,即使此后有其他操作介入。
static final int PROPAGATE = -3;

//0:以上数值均未按数字排列以简化使用。非负值表示节点不需要发出信号。所以,大多数代码不需要检查特定的值,只需要检查符号。
//对于正常同步节点,该字段初始化为0;对于条件节点,该字段初始化为条件。它是使用CAS修改的(或者在可能的情况下,使用无条件的volatile写入)。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

SIGNAL

从上面的注释介绍可以明白,只有上一个节点是SIGNAL,当前节点才有可能被上一个节点唤醒。
在这里插入图片描述

总结:

  1. 如果只有一个线程进来不会初始化CHL同步得带队列
  2. 第二个线程来加锁失败(竞争)时,会帮头节点初始化一个节点,并将自己的节点挂再头节点后面
  3. 每个等待的节点会将上一个节点的状态改为SIGNAL(-1),用来标志改节点后面的节点才可以被唤醒
  4. 在释放锁的时候如果头节点的状态为不为0,会先将其设置为0。然后唤醒下一个节点
  5. 节点入队和唤醒的时候都会跳过ws>0 即CANCELLED(取消)的节点
  6. 头节点一定表示当前获取锁的线程节点。

CANCELLED

由于超时或中断,此节点被取消。节点一旦被取消了就不会再改变状态。特别是,取消节点的线程不会再阻塞。

从中断线程案例开始:

public class NonFairReentrantLock extends AbstractQueuedSynchronizer {

    public static void main(String[] args) {

        final ReentrantLock lock = new ReentrantLock();

        List<Thread> threads = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread("线程: " + i) {
                @Override
                public void run() {
                    try {
                        lock.lockInterruptibly(); // 如果线程被中断了在这里会抛出异常
                        // ... method body
                        System.out.println(Thread.currentThread().getName() + " 开始执行!");
                        Thread.sleep(100);
                        System.out.println(Thread.currentThread().getName() + " 执行结束!");
                    } catch (InterruptedException e) {
                        // 这里处理线程中断的后续逻辑
                        System.out.println(Thread.currentThread().getName() + "  被打断!");
                    } finally {
                        lock.unlock();
                    }
                }
            };
            threads.add(thread);
            thread.start();
        }

        // 会在线程上打上一个interrupt标记
        threads.get(3).interrupt();
        // 主线程阻塞
        LockSupport.park();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

输出结果:

线程: 0 开始执行!
Exception in thread "线程: 3" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
线程: 3  被打断!
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
	at concurrent.reentrantLockDemo.NonFairReentrantLock$1.run(NonFairReentrantLock.java:30)
线程: 0 执行结束!
线程: 1 开始执行!
线程: 1 执行结束!
线程: 2 开始执行!
线程: 2 执行结束!
线程: 4 开始执行!
线程: 4 执行结束!
线程: 5 开始执行!
线程: 5 执行结束!
线程: 6 开始执行!
线程: 6 执行结束!
线程: 7 开始执行!
线程: 7 执行结束!
线程: 8 开始执行!
线程: 8 执行结束!
线程: 9 开始执行!
线程: 9 执行结束!

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这里插入图片描述

下面两种状态下篇博客

CONDITION

结合BlockingQueue 案例说明

PROPAGATE

结合Semaphore案例说明

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/149132
推荐阅读
相关标签
  

闽ICP备14008679号