八、AQS简述

58 阅读2分钟

AQS内部结构

AQS就是java中的AbstractQueuedSynchronizer类,属于JUC包下的基类,JUC包下的很多类都继承了AQS。例如:ReentrantLock、ThreadPoolExecutor等

常见的属性变量

state

private volatile int state;

state:由volatile修饰的,int类型的属性变量

通过CAS方式对state变量值进行修改,保证原子性

node

static final class Node {

	static final Node SHARED = new Node();

	static final Node EXCLUSIVE = null;

	static final int CANCELLED =  1;    // 表示节点已经被取消,即将从队列中删除

	static final int SIGNAL    = -1;    // 表示此节点后面还有待唤醒的节点

	static final int CONDITION = -2;

	static final int PROPAGATE = -3;

	volatile int waitStatus;

	volatile Node prev;

	volatile Node next;

	volatile Thread thread;

	Node nextWaiter;

	final boolean isShared() {
		return nextWaiter == SHARED;
	}

	final Node predecessor() throws NullPointerException {
		Node p = prev;
		if (p == null)
			throw new NullPointerException();
		else
			return p;
	}

	Node() {   
	}

	Node(Thread thread, Node mode) {    
		this.nextWaiter = mode;
		this.thread = thread;
	}

	Node(Thread thread, int waitStatus) { 
		this.waitStatus = waitStatus;
		this.thread = thread;
	}
}

node:内部类,是双向链表的节点类型,而且node中存储了一个线程

node中的属性变量:

  1. SHARED:表示共享锁
  2. EXCLUSIVE:表示排他锁
  3. CANCELLED、SIGNAL、CONDITION、PROPAGATE表示线程状态,即waitStatus的取值

AQS的对象抽象模型

image.png

AQS的加锁过程

非公平锁的加锁过程

前提:线程A和线程B抢夺锁资源

1、线程A和线程B通过CAS的方式将state变量值从0改成1,谁成功了,谁就获得锁了

2、假设线程A成功了,此时线程B被封装成node对象

3、node对象的线程变量是线程B,互斥锁,waitStatus的值是0

4、将node对象放到双向链表的尾部,并且将线程的状态变成挂起

5、双向链表的头节点是个伪节点,伪节点中thread变量值为null

6、每当有新的node节点添加到链表中,前一个节点的waitStatus值从0变成-1,表示后面存在挂起的节点

加锁流程示意图:

image.png