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,当前节点才有可能被上一个节点唤醒。
总结:
- 如果只有一个线程进来不会初始化CHL同步得带队列
- 第二个线程来加锁失败(竞争)时,会帮头节点初始化一个节点,并将自己的节点挂再头节点后面
- 每个等待的节点会将上一个节点的状态改为SIGNAL(-1),用来标志改节点后面的节点才可以被唤醒
- 在释放锁的时候如果头节点的状态为不为0,会先将其设置为0。然后唤醒下一个节点
- 节点入队和唤醒的时候都会跳过ws>0 即CANCELLED(取消)的节点
- 头节点一定表示当前获取锁的线程节点。
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 执行结束!
复制代码
下面两种状态下篇博客
CONDITION
结合BlockingQueue 案例说明
PROPAGATE
结合Semaphore案例说明