亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

Java CopyOnWrite容器實現分析

2023-10-27 06:28:55
5
0

CopyOnWrite是一種優化策略,當在并發寫時,通過復制出原內容,在新的內容上讀寫,然后再把新的內容指向原來內容的引用。通過這種策略實現并發時,讀寫互不干涉,類似讀寫分離,來提升性能。
CopyOnWrite容器是寫時復制容器,實現讀無鎖,提高讀的并發性能。 Java目前提供了兩個CopyOnWrite容器,分別為CopyOnWriteArrayList和CopyOnWriteArraySet,CopyOnWriteArraySet的實現完全是通過CopyOnWriteArrayList來實現的,它持有一個final的CopyOnWriteArrayList引用,把方法調用都委托給CopyOnWriteArrayList來調用。

下面只研究CopyOnWriteArrayList的實現:

一、CopyOnWriteArrayList的結構

CopyOnWriteArrayList的結構比較簡單,它只包含了兩個成員變量:volatile的array對象數組和ReentrantLock對象。volatile的array引用可以保證修改時對其它線程可見,ReentrantLock鎖主要運用在對數組的寫操作上。

二、主要方法實現分析

1、add的相關方法實現
add有3個方法,一個是直接添加到數組中,一個是添加到數組中的指定位置,還有一個是如果數組中沒有元素時才添加成功的方法,主要是給CopyOnWriteArraySet使用,相關代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//加鎖
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
//copy一份新的數組,長度是原來的數組長度+1
Object[] newElements = Arrays.copyOf(elements, len + 1);
//把元素添加到新數組的最后位置
newElements[len] = e;
//設置數組引用指向新數組
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
public void add(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements;
int numMoved = len - index;
//如果添加的位置是最后
if (numMoved == 0)
newElements = Arrays.copyOf(elements, len + 1);
else {
//創建一份長度是原數組長度+1的新數組
newElements = new Object[len + 1];
//把原來的數組從0-index復制到新數組中
System.arraycopy(elements, 0, newElements, 0, index);
//把原來的數組從index-numMoved復制到新數組中
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
//把元素添加到新數組的index位置
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}
public boolean addIfAbsent(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// Copy while checking if already present.
// This wins in the most common case where it is not present
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = new Object[len + 1];
for (int i = 0; i < len; ++i) {
if (eq(e, elements[i]))
return false; // exit, throwing away copy
else
newElements[i] = elements[i];
}
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}

從上面的代碼可以看出,3者的實現大同小異,主要流程如下:
1).首先加鎖,然后獲取舊數組,復制出一份新數組,然后在新數組上添加元素,最后把對象數組的引用指用新數組;
2).不同的是add(E e)直接把添加的元素添加到新數組的最后位置,而add(int index ,E e)方法在復制舊數組時不同,需要計算出index前后的長度,再復制;addIfAbsent(E e)則是會判斷數組中是否已經存在要添加的元素,如果存在返回false。

2、get方法實現
get方法實現很簡單,直接從array數組引用的下標找到對應的元素返回即可:

1
2
3
public E get(int index) {
return (E)(getArray()[index]);
}

其它的方法實現也很簡單,涉及到更新數組的操作都會加鎖和復制新數組。

三、總結

CopyOnWrite是典型的以空間換時間的模型,實現的容器優點和缺點都突出,優點是性能非常高,因為沒有鎖。但存在兩個問題,第一是內存占用會很高,因為在復制出新數組后,舊的數組中的對象并不會馬上銷毀,如果數組很大,且并發更新很高時,搞不好會出現內存溢出。可以通過一些方法壓縮內容,避免這種問題;第二是存在內存一致性問題,雖然最終內存還是一致的,但如果在復制新數組過程中,引用還未指向新數組時,線程訪問會出現讀不到新的元素。

0條評論
作者已關閉評論
chuoo
13文章數
0粉絲數
chuoo
13 文章 | 0 粉絲
原創

Java CopyOnWrite容器實現分析

2023-10-27 06:28:55
5
0

CopyOnWrite是一種優化策略,當在并發寫時,通過復制出原內容,在新的內容上讀寫,然后再把新的內容指向原來內容的引用。通過這種策略實現并發時,讀寫互不干涉,類似讀寫分離,來提升性能。
CopyOnWrite容器是寫時復制容器,實現讀無鎖,提高讀的并發性能。 Java目前提供了兩個CopyOnWrite容器,分別為CopyOnWriteArrayList和CopyOnWriteArraySet,CopyOnWriteArraySet的實現完全是通過CopyOnWriteArrayList來實現的,它持有一個final的CopyOnWriteArrayList引用,把方法調用都委托給CopyOnWriteArrayList來調用。

下面只研究CopyOnWriteArrayList的實現:

一、CopyOnWriteArrayList的結構

CopyOnWriteArrayList的結構比較簡單,它只包含了兩個成員變量:volatile的array對象數組和ReentrantLock對象。volatile的array引用可以保證修改時對其它線程可見,ReentrantLock鎖主要運用在對數組的寫操作上。

二、主要方法實現分析

1、add的相關方法實現
add有3個方法,一個是直接添加到數組中,一個是添加到數組中的指定位置,還有一個是如果數組中沒有元素時才添加成功的方法,主要是給CopyOnWriteArraySet使用,相關代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//加鎖
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
//copy一份新的數組,長度是原來的數組長度+1
Object[] newElements = Arrays.copyOf(elements, len + 1);
//把元素添加到新數組的最后位置
newElements[len] = e;
//設置數組引用指向新數組
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
public void add(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements;
int numMoved = len - index;
//如果添加的位置是最后
if (numMoved == 0)
newElements = Arrays.copyOf(elements, len + 1);
else {
//創建一份長度是原數組長度+1的新數組
newElements = new Object[len + 1];
//把原來的數組從0-index復制到新數組中
System.arraycopy(elements, 0, newElements, 0, index);
//把原來的數組從index-numMoved復制到新數組中
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
//把元素添加到新數組的index位置
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}
public boolean addIfAbsent(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// Copy while checking if already present.
// This wins in the most common case where it is not present
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = new Object[len + 1];
for (int i = 0; i < len; ++i) {
if (eq(e, elements[i]))
return false; // exit, throwing away copy
else
newElements[i] = elements[i];
}
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}

從上面的代碼可以看出,3者的實現大同小異,主要流程如下:
1).首先加鎖,然后獲取舊數組,復制出一份新數組,然后在新數組上添加元素,最后把對象數組的引用指用新數組;
2).不同的是add(E e)直接把添加的元素添加到新數組的最后位置,而add(int index ,E e)方法在復制舊數組時不同,需要計算出index前后的長度,再復制;addIfAbsent(E e)則是會判斷數組中是否已經存在要添加的元素,如果存在返回false。

2、get方法實現
get方法實現很簡單,直接從array數組引用的下標找到對應的元素返回即可:

1
2
3
public E get(int index) {
return (E)(getArray()[index]);
}

其它的方法實現也很簡單,涉及到更新數組的操作都會加鎖和復制新數組。

三、總結

CopyOnWrite是典型的以空間換時間的模型,實現的容器優點和缺點都突出,優點是性能非常高,因為沒有鎖。但存在兩個問題,第一是內存占用會很高,因為在復制出新數組后,舊的數組中的對象并不會馬上銷毀,如果數組很大,且并發更新很高時,搞不好會出現內存溢出。可以通過一些方法壓縮內容,避免這種問題;第二是存在內存一致性問題,雖然最終內存還是一致的,但如果在復制新數組過程中,引用還未指向新數組時,線程訪問會出現讀不到新的元素。

文章來自個人專欄
文章 | 訂閱
0條評論
作者已關閉評論
作者已關閉評論
0
0