Skip to content

Commit 822856d

Browse files
committed
[A] list:CopyOnWriteArrayList && map:EnumMap&IdentityHashMap
1 parent 2275887 commit 822856d

File tree

5 files changed

+314
-3
lines changed

5 files changed

+314
-3
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414
## 目录简介
1515

16-
<a href=".">.</a><br>
16+
<h1>Directory Tree</h1><p>
17+
<a href=".">.</a><br>
1718
├── <a href="./README.md">README.md</a><br>
1819
├── <a href="./algo/">algo</a><br>
1920
│ ├── <a href="./algo/leetcode-148-Sort-List(%E5%8D%95%E9%93%BE%E8%A1%A8%E6%8E%92%E5%BA%8F).md">leetcode-148-Sort-List(单链表排序).md</a><br>
@@ -49,7 +50,13 @@
4950
│ │ └── <a href="./java/source-code/jdk/">jdk</a><br>
5051
│ │ &nbsp;&nbsp;&nbsp; ├── <a href="./java/source-code/jdk/collection/">collection</a><br>
5152
│ │ &nbsp;&nbsp;&nbsp; │ ├── <a href="./java/source-code/jdk/collection/collection.md">collection.md</a><br>
52-
│ │ &nbsp;&nbsp;&nbsp; │ └── <a href="./java/source-code/jdk/collection/list-arraylist.md">list-arraylist.md</a><br>
53+
│ │ &nbsp;&nbsp;&nbsp; │ ├── <a href="./java/source-code/jdk/collection/list-arraylist.md">list-arraylist.md</a><br>
54+
│ │ &nbsp;&nbsp;&nbsp; │ ├── <a href="./java/source-code/jdk/collection/list-copyonwritearraylist.md">list-copyonwritearraylist.md</a><br>
55+
│ │ &nbsp;&nbsp;&nbsp; │ ├── <a href="./java/source-code/jdk/collection/list-linkedlist.md">list-linkedlist.md</a><br>
56+
│ │ &nbsp;&nbsp;&nbsp; │ ├── <a href="./java/source-code/jdk/collection/list-stack.md">list-stack.md</a><br>
57+
│ │ &nbsp;&nbsp;&nbsp; │ ├── <a href="./java/source-code/jdk/collection/list-vector.md">list-vector.md</a><br>
58+
│ │ &nbsp;&nbsp;&nbsp; │ ├── <a href="./java/source-code/jdk/collection/map-enummap.md">map-enummap.md</a><br>
59+
│ │ &nbsp;&nbsp;&nbsp; │ └── <a href="./java/source-code/jdk/collection/map-identityhashmap.md">map-identityhashmap.md</a><br>
5360
│ │ &nbsp;&nbsp;&nbsp; └── <a href="./java/source-code/jdk/lang/">lang</a><br>
5461
│ │ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; └── <a href="./java/source-code/jdk/lang/integer.md">integer.md</a><br>
5562
│ ├── <a href="./java/test/">test</a><br>
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# CopyOnWriteArrayList
2+
3+
写时复制底层数组,新数组的引用会直接替换老的数组引用,复制开销较大,适合用于读远远超过写的频率。
4+
5+
线程安全。
6+
7+
## 设计思路
8+
9+
读写分离。
10+
11+
读操作时会先拿到数组的引用,写时复制后写入新数组
12+
13+
```java
14+
public int indexOf(Object o) {
15+
// 读操作先拿数组引用
16+
Object[] elements = getArray();
17+
return indexOf(o, elements, 0, elements.length);
18+
}
19+
```
20+
21+
```java
22+
public boolean add(E e) {
23+
final ReentrantLock lock = this.lock;
24+
lock.lock();
25+
try {
26+
Object[] elements = getArray();
27+
int len = elements.length;
28+
// 写前先复制,并发过来的读请求会使用旧数组
29+
Object[] newElements = Arrays.copyOf(elements, len + 1);
30+
newElements[len] = e;
31+
setArray(newElements);
32+
return true;
33+
} finally {
34+
lock.unlock();
35+
}
36+
}
37+
```
38+
39+
## 迭代器遍历
40+
41+
不支持修改,因为 snapshot 为创建迭代器时的数组引用,这个数组在迭代期间不会被修改,因为写操作时会复制新的数组,所以在遍历时不会有 `ConcurrentModificationException`
42+
43+
```java
44+
static final class COWIterator<E> implements ListIterator<E> {
45+
/** Snapshot of the array */
46+
private final Object[] snapshot;
47+
/** Index of element to be returned by subsequent call to next. */
48+
private int cursor;
49+
50+
/**
51+
* Not supported. Always throws UnsupportedOperationException.
52+
* @throws UnsupportedOperationException always; {@code remove}
53+
* is not supported by this iterator.
54+
*/
55+
public void remove() {
56+
throw new UnsupportedOperationException();
57+
}
58+
59+
/**
60+
* Not supported. Always throws UnsupportedOperationException.
61+
* @throws UnsupportedOperationException always; {@code set}
62+
* is not supported by this iterator.
63+
*/
64+
public void set(E e) {
65+
throw new UnsupportedOperationException();
66+
}
67+
68+
/**
69+
* Not supported. Always throws UnsupportedOperationException.
70+
* @throws UnsupportedOperationException always; {@code add}
71+
* is not supported by this iterator.
72+
*/
73+
public void add(E e) {
74+
throw new UnsupportedOperationException();
75+
}
76+
}
77+
```
78+
79+
## 可重入锁保证一致性
80+
81+
```java
82+
public boolean add(E e) {
83+
final ReentrantLock lock = this.lock;
84+
lock.lock();
85+
try {
86+
Object[] elements = getArray();
87+
int len = elements.length;
88+
Object[] newElements = Arrays.copyOf(elements, len + 1);
89+
newElements[len] = e;
90+
setArray(newElements);
91+
return true;
92+
} finally {
93+
lock.unlock();
94+
}
95+
}
96+
```
97+
98+
## 开源组件拓展
99+
100+
### Apollo
101+
102+
apollo 使用 `CopyOnWriteArrayList` 维护配置变更监听器列表。非常典型的读多写少场景。
103+
104+
// 有个问题,因为这个 list 每次都是添加一个监听器,若监听器比较多,性能有点尴尬。
105+
106+
[Apollo配置中心介绍#36-客户端监听配置变化](https://github.com/ctripcorp/apollo/wiki/Apollo%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E4%BB%8B%E7%BB%8D#36-%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9B%91%E5%90%AC%E9%85%8D%E7%BD%AE%E5%8F%98%E5%8C%96)
107+
108+
## 最后
109+
110+
- [并发容器之CopyOnWriteArrayList - 你听___](https://juejin.im/post/5aeeb55f5188256715478c21)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# `EnumMap<K extends Enum<K>, V>`
2+
3+
## 设计亮点
4+
5+
key-value 使用数组代替普通的哈希表,很赞的设计。
6+
7+
```java
8+
/**
9+
* All of the values comprising K. (Cached for performance.)
10+
*/
11+
private transient K[] keyUniverse;
12+
13+
/**
14+
* Array representation of this map. The ith element is the value
15+
* to which universe[i] is currently mapped, or null if it isn't
16+
* mapped to anything, or NULL if it's mapped to null.
17+
*/
18+
private transient Object[] vals;
19+
```
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# `IdentityHashMap<K,V>`
2+
3+
线性探测实现,key 为引用,判断 key 相等使用 `==` 而不是 `equals`
4+
5+
## 容量
6+
7+
```java
8+
/**
9+
* The initial capacity used by the no-args constructor.
10+
* MUST be a power of two. The value 32 corresponds to the
11+
* (specified) expected maximum size of 21, given a load factor
12+
* of 2/3.
13+
*/
14+
private static final int DEFAULT_CAPACITY = 32;
15+
16+
/**
17+
* The minimum capacity, used if a lower value is implicitly specified
18+
* by either of the constructors with arguments. The value 4 corresponds
19+
* to an expected maximum size of 2, given a load factor of 2/3.
20+
* MUST be a power of two.
21+
*/
22+
private static final int MINIMUM_CAPACITY = 4;
23+
24+
/**
25+
* The maximum capacity, used if a higher value is implicitly specified
26+
* by either of the constructors with arguments.
27+
* MUST be a power of two <= 1<<29.
28+
*
29+
* In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
30+
* because it has to have at least one slot with the key == null
31+
* in order to avoid infinite loops in get(), put(), remove()
32+
*/
33+
private static final int MAXIMUM_CAPACITY = 1 << 29;
34+
35+
/**
36+
* Returns the appropriate capacity for the given expected maximum size.
37+
* Returns the smallest power of two between MINIMUM_CAPACITY and
38+
* MAXIMUM_CAPACITY, inclusive, that is greater than (3 *
39+
* expectedMaxSize)/2, if such a number exists. Otherwise returns
40+
* MAXIMUM_CAPACITY.
41+
*/
42+
private static int capacity(int expectedMaxSize) {
43+
// assert expectedMaxSize >= 0;
44+
return
45+
// 期待容量大于最大容量的 1/3 直接使用最大容量
46+
(expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
47+
// 期待容量小于等于最小容量的 2/3 直接使用最小容量
48+
(expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
49+
// 使用大于期待容量3倍的最小 2^n 次数作为容量
50+
Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
51+
}
52+
53+
/**
54+
* Initializes object to be an empty map with the specified initial
55+
* capacity, which is assumed to be a power of two between
56+
* MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.
57+
*/
58+
private void init(int initCapacity) {
59+
// assert (initCapacity & -initCapacity) == initCapacity; // power of 2
60+
// assert initCapacity >= MINIMUM_CAPACITY;
61+
// assert initCapacity <= MAXIMUM_CAPACITY;
62+
63+
table = new Object[2 * initCapacity];
64+
}
65+
```
66+
67+
## 开源组件拓展
68+
69+
最核心的是 `AnnotationAwareOrderComparator`
70+
71+
### Spring bean 排序
72+
73+
`DefaultListableBeanFactory``FactoryAwareOrderSourceProvider` 用于保存 bean instace 到 beanName 的 mapping,spring 框架使用 bean 的引用查找对应的 beanName, 然后查找对应的 `RootBeanDefinition` 然后确定 bean 的优先级。因为 instance 是引用,不适合使用 equals 来判断相等性,因为同一个类的实例,equals 判断相等,但是实际对应两个对象,这种情况转换 beanName -> instance 转为 instance->beanName 的过程会丢 bean,所以只能使用引用来判断相等性,所以需要使用 `IdentityHashMap`
74+
75+
```java
76+
private OrderComparator.OrderSourceProvider createFactoryAwareOrderSourceProvider(Map<String, ?> beans) {
77+
IdentityHashMap<Object, String> instancesToBeanNames = new IdentityHashMap<>();
78+
beans.forEach((beanName, instance) -> instancesToBeanNames.put(instance, beanName));
79+
return new FactoryAwareOrderSourceProvider(instancesToBeanNames);
80+
}
81+
```
82+
83+
```java
84+
/**
85+
* An {@link org.springframework.core.OrderComparator.OrderSourceProvider} implementation
86+
* that is aware of the bean metadata of the instances to sort.
87+
* <p>Lookup for the method factory of an instance to sort, if any, and let the
88+
* comparator retrieve the {@link org.springframework.core.annotation.Order}
89+
* value defined on it. This essentially allows for the following construct:
90+
*/
91+
private class FactoryAwareOrderSourceProvider implements OrderComparator.OrderSourceProvider {
92+
93+
private final Map<Object, String> instancesToBeanNames;
94+
95+
public FactoryAwareOrderSourceProvider(Map<Object, String> instancesToBeanNames) {
96+
this.instancesToBeanNames = instancesToBeanNames;
97+
}
98+
99+
@Override
100+
@Nullable
101+
public Object getOrderSource(Object obj) {
102+
// 根据引用,拿到 beanName,用 beanName 查找对应的 RootBeanDefinition
103+
RootBeanDefinition beanDefinition = getRootBeanDefinition(this.instancesToBeanNames.get(obj));
104+
if (beanDefinition == null) {
105+
return null;
106+
}
107+
List<Object> sources = new ArrayList<>(2);
108+
Method factoryMethod = beanDefinition.getResolvedFactoryMethod();
109+
if (factoryMethod != null) {
110+
sources.add(factoryMethod);
111+
}
112+
Class<?> targetType = beanDefinition.getTargetType();
113+
if (targetType != null && targetType != obj.getClass()) {
114+
sources.add(targetType);
115+
}
116+
return sources.toArray();
117+
}
118+
119+
@Nullable
120+
private RootBeanDefinition getRootBeanDefinition(@Nullable String beanName) {
121+
if (beanName != null && containsBeanDefinition(beanName)) {
122+
BeanDefinition bd = getMergedBeanDefinition(beanName);
123+
if (bd instanceof RootBeanDefinition) {
124+
return (RootBeanDefinition) bd;
125+
}
126+
}
127+
return null;
128+
}
129+
}
130+
```
131+
132+
### `HttpMessageConverter`
133+
134+
```java
135+
@Configuration
136+
public class HttpMessageConverterConfig {
137+
@Bean
138+
@Order(1)
139+
public HttpMessageConverter<String> messageConverter1() {
140+
return new StringHttpMessageConverter(StandardCharsets.UTF_8);
141+
}
142+
143+
@Bean
144+
@Order(2)
145+
public HttpMessageConverter<String> messageConverter2() {
146+
return new StringHttpMessageConverter(StandardCharsets.UTF_8);
147+
}
148+
149+
@Bean
150+
@Order(3)
151+
public HttpMessageConverter<String> messageConverter3() {
152+
return new StringHttpMessageConverter(StandardCharsets.UTF_8);
153+
}
154+
}
155+
```
156+
157+
### `ApplicationContextInitializer`
158+
159+
```java
160+
@Order(1)
161+
public class ApplicationContextInitializer1 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
162+
@Override
163+
public void initialize(ConfigurableApplicationContext applicationContext) {
164+
System.out.println(this.getClass().getName());
165+
}
166+
}
167+
168+
@Order(2)
169+
public class ApplicationContextInitializer2 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
170+
@Override
171+
public void initialize(ConfigurableApplicationContext applicationContext) {
172+
System.out.println(this.getClass().getName());
173+
}
174+
}
175+
```

res/java-collection-framework-list.pu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
interface Collection<E>
44
class AbstractCollection<E>
55
interface List<E>
6-
class CopyOnWriteArrayList<E>
6+
class CopyOnWriteArrayList<E> #Darkorange
77
class AbstractList<E>
88
class ArrayList<E>
99
class AbstractSequentialList<E>

0 commit comments

Comments
 (0)