AQS中那些waitStatus(一)

系列文章目录

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


目录

  • 系列文章目录
  • waitStatus有哪些
  • SIGNAL
      • 总结:
  • CANCELLED
    • 下面两种状态下篇博客
  • CONDITION
  • PROPAGATE

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写入)。

SIGNAL

从上面的注释介绍可以明白,只有上一个节点是SIGNAL,当前节点才有可能被上一个节点唤醒。
AQS中那些waitStatus(一)_第1张图片

总结:

  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();
    }

}

输出结果:

线程: 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 执行结束!

AQS中那些waitStatus(一)_第2张图片

下面两种状态下篇博客

CONDITION

结合BlockingQueue 案例说明

PROPAGATE

结合Semaphore案例说明

你可能感兴趣的:(并发编程,多线程,java,并发编程,thread)