文末
我将这三次阿里面试的题目全部分专题整理出来,并附带上详细的答案解析,生成了一份PDF文档
- 第一个要分享给大家的就是算法和数据结构
- 第二个就是数据库的高频知识点与性能优化
- 第三个则是并发编程(72个知识点学习)
- 最后一个是各大JAVA架构专题的面试点+解析+我的一些学习的书籍资料
还有更多的Redis、MySQL、JVM、Kafka、微服务、Spring全家桶等学习笔记这里就不一一列举出来
if (ws > 0) {
// 找到前一个状态不是取消的节点,因为把当前 node 挂在有效节点的身上
// 因为节点的状态是取消的话,是无效的,是不能作为 node 的前置节点的,所以必须找到 node 的有效节点才行
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
// 否则直接把节点状态设置为 signal
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
acquire 整个过程非常长,代码也非常多,但注释很清楚,可以一行一行仔细看看代码。
1.1.5 总结
acquire 方法大致分为三步:
-
使用 tryAcquire 方法尝试获得锁,获得锁直接返回,获取不到锁的走 2;
-
把当前线程组装成节点(Node),追加到同步队列的尾部(addWaiter);
-
自旋,使同步队列中当前节点的前置节点状态为 signal 后,然后阻塞自己。
acquireShared 整体流程和 acquire 相同,代码也很相似,重复的源码就不贴了,我们就贴出来不一样的代码来,也方便大家进行比较:
- 第一处尝试获得锁的地方,有所不同,排它锁使用的是 tryAcquire 方法,共享锁使用的是 tryAcquireShared 方法,如下图:
- 第二处不同,在于节点获得排它锁时,仅仅把自己设置为同步队列的头节点即可(setHead 方法),但如果是共享锁的话,还会去唤醒自己的后续节点,一起来获得该锁(setHeadAndPropagate 方法),不同之处如下(左边排它锁,右边共享锁):
1.2.1 setHeadAndPropagate
这个方法主要做了两件事:
-
把当前节点设置成头节点
-
看看后续节点有无正在等待,并且也是共享模式的,有的话唤醒这些节点
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head;
// 当前节点设置成头节点
setHead(node);
// propagate > 0 表示已经有节点获得共享锁了
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) ==