AbstractQueuedSynchronizer
是并发的基础组件,简称AQS
,今天就对其部分源码一探究竟吧
推荐参考博客
AbstractQueuedSynchronizer的介绍和原理分析
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
上面的方法首先就是让当前线程获取锁,获取到了直接退出该方法,如果没有获取到则调用acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
方法,将其加入到同步队列中去。
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
这个方法虽然没有设置为抽象的方法但是却不能直接使用,需要子类重写该方法。作者之所以不将其定义为抽象方法,我想主要是因为这个类的功能很多,可以使用该类写出独占或是共享式的锁,二者两种锁,并不需要重写这个类中所有的类似上面的方法,如果是抽象的方法,用不到的方法也要进行重写,这是相当不必要的。
tryAcquire
独占式简单实现:
public boolean tryAcquire(int acquires) {
- 只有一个线程能更改该state属性,这就对应着只有一个线程可以获取锁。
更改state属性值(获取锁)失败的线程要进入同步队列中,这就对应着没有获取锁的线
程会进入堵塞队列中,等待获取锁的线程释放锁。
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
通过简单对AQS
的状态属性进行更改,实现获取锁。
其实这里很多人可能无法理解,为什么这样就是获取了锁,java中的synchronized同步锁其实就是通过对象头中的信息判断的,且jvm保证了只要一个线程可以获取锁,这里要实现锁,就是通过一个volatile成员属性,然后CAS保证原子性,对应内存语义就是锁的概念。
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
private Node addWaiter(Node mode) {
- 将当前线程构造成一个节点,加入到同步队列中
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
对应获取锁(更改state
值)失败的线程,将会执行上面的方法进入同步队列中
未完待续...写的太菜了,哈哈
网友评论