Skip to content

Commit f83a49e

Browse files
committed
谈谈AQS.md
1 parent ea73d34 commit f83a49e

2 files changed

Lines changed: 117 additions & 7 deletions

File tree

Interview/sad/谈谈AQS.md

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,65 @@
1-
> 这个先留着,这个内容有点多,待我这周结束之后来写。
1+
> 这个先留着,这个内容有点多,待我这周结束之后来写。
2+
3+
面试官:AQS是什么?
4+
5+
我:AbstractQueuedSynchronizer抽象同步队列。说白了,就是个FIFO双向队列。其内部通过节点head和tail记录对首和队尾元素。
6+
7+
**state**:在AQS中维持了一个单一的状态信息state,可以通过**getState****setState****compareAndSetState**函数修改其值。
8+
9+
- **ReentrantLock**:state可以用来表示当前线程获取锁的可重入次数。
10+
11+
- **ReentrantReadWriteLock**:state的高16位表示读状态,也就是获取该读锁的次数,低16位表示获取到写锁的线程的可重入次数。
12+
- **semaphore**:state用来表示当前可用信号的个数。
13+
- **CountDownlatch**:state用来表示计数器当前的值。
14+
15+
对于AQS来讲,线程同步的关键是对状态值**state**进行操作。
16+
17+
在独占方式下获取和释放资源使用的方法:
18+
19+
```java
20+
void acquire(int arg);
21+
void acquireInterruptibly(int arg);
22+
boolean release(int arg);
23+
```
24+
25+
在共享方式获取和释放资源使用的方法:
26+
27+
```java
28+
void acquireShared(int arg);
29+
void acquireSharedInterruptibly(int arg);
30+
boolean releaseShared(int arg);
31+
```
32+
33+
使用独占方式获取的资源是与**具体线程绑定**的,就是说如果一个线程获取到了资源,就会标记是这个线程获取到了,其他线程再尝试操作state获取资源时会**发现当前该资源不是自己持有的**,就会在**获取失败后被阻塞**。(比如ReentrantLock)
34+
35+
对应的共享方式的资源与具体线程是不相关的,当多个线程去请求资源时通过CAS方式竞争获取资源,当一个线程获取到了资源后,另外一个线程再次去获取时如果当前资源还能满足它的资源,则当前线程只需要使用CAS方式进行获取即可。(比如semaphore)
36+
37+
看一下**acquire**方法:
38+
39+
```java
40+
// tryAcquire 具体的子类去实现,并维护state的状态
41+
public final void acquire(int arg) {
42+
if (!tryAcquire(arg) &&
43+
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 如果失败标记状态,入队
44+
selfInterrupt();
45+
}
46+
```
47+
48+
看一下**release**方法:
49+
50+
```java
51+
// tryRelease 具体的子类是实现,并设置state的状态
52+
public final boolean release(int arg) {
53+
if (tryRelease(arg)) {
54+
Node h = head;
55+
if (h != null && h.waitStatus != 0)
56+
unparkSuccessor(h); // 调用unpark唤醒队列的线程,并调用tryAcquire尝试,看是否需要,如果不需要,继续挂起
57+
return true;
58+
}
59+
return false;
60+
}
61+
```
62+
63+
**acquireShared和releaseShared**和上面的方法的思想差不多
64+
65+

Interview/src/Main.java

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
11
import java.util.ArrayList;
2-
import java.util.Arrays;
32
import java.util.List;
43

54
public class Main {
6-
public int[][] merge(int[][] intervals) {
7-
StringBuilder sb = new StringBuilder();
8-
sb.cha
5+
public static void main(String[] args) {
6+
int[] nums = {3, 2, 1, 6, 5, 4};
7+
ListNode node = ListNodeTools.getListNode(nums);
8+
ListNodeTools.printListNode(node);
9+
reorderList(node);
10+
ListNodeTools.printListNode(node);
911
}
10-
}
1112

13+
public static void reorderList(ListNode head) {
14+
List<Integer> list = new ArrayList<>();
15+
ListNode p = head;
16+
while (p != null) {
17+
list.add(p.val);
18+
p = p.next;
19+
}
20+
int l = 0, r = list.size() - 1;
21+
int idx = 0;
22+
int[] nums = new int[list.size()];
23+
while (l < r) {
24+
nums[idx++] = list.get(l++);
25+
nums[idx++] = list.get(r--);
26+
}
27+
p = head;
28+
idx = 0;
29+
while (p != null) {
30+
p.val = nums[idx++];
31+
p = p.next;
32+
}
33+
}
34+
}
1235

1336
class TreeNode {
1437
int val;
@@ -24,4 +47,27 @@ class ListNode {
2447
public ListNode(int val) {
2548
this.val = val;
2649
}
27-
}
50+
}
51+
52+
53+
class ListNodeTools {
54+
public static ListNode getListNode(int[] nums) {
55+
ListNode dummy = new ListNode(-1);
56+
ListNode pre = dummy;
57+
for (int num : nums) {
58+
pre.next = new ListNode(num);
59+
pre = pre.next;
60+
}
61+
return dummy.next;
62+
}
63+
64+
public static void printListNode(ListNode node) {
65+
String s = "";
66+
ListNode p = node;
67+
while (p != null) {
68+
s += p.val + "->";
69+
p = p.next;
70+
}
71+
System.out.println(s+"null");
72+
}
73+
}

0 commit comments

Comments
 (0)