網站首頁 編程語言 正文
文章目錄
- ArrayList和CopyOnWriteArrayList
- 1.Se()方法
- 2.add()方法
- 3.add()添加指定位置的元素
- 4.Remove()方法
- 總結
ArrayList和CopyOnWriteArrayList
我們知道多線程并發時ArraysList是線程不安全,而CopyOnWriteArrayList是線程安全,那么CopyOnWriteArrayList是如何保證線程安全的呢?通過以下常用的方法說明:
1.Se()方法
首先兩個set()方法的作用是一樣的都是替換指定位置的值,但CopyOnWriteArrayList中的set()方法實現ReentrantLock加鎖機制,這就是為什么CopyOnWriteArrayList是線程安全。CopyOnWriteArrayList中通過getArray()方法得到原來的數組可理解為oldArray[ ];再通過get(elements, index)方法將原來該下標位置的值取出即為oldValue;然后判斷要修改的值是否與原來的值相等,如果相等則將原數組重新放回,如果不相等則進行元素替換通過Arrays.copyOf(elements, len)方法復制新的數組,將指定位置的值進行修改;最后將修改完的數組放回并釋放鎖
ArrayList的set()方法
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
CopyOnWriteArrayList的set()方法
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
2.add()方法
同理,CopyOnWriteArrayList中的add()方法是實現ReentrantLock鎖機制也是線程安全。也是通過getArray()得到原來數組;再通過Arrays.copyOf(elements, len + 1)方法復制原來的數組oldArray[ ],但比原數組的長度多1,是因為將要添加的元素采用尾插法存儲至數組尾部;最后依舊將新數組放回并釋放鎖
ArrayList的add()方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
CopyOnWriteArrayList的add()方法
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
3.add()添加指定位置的元素
通過getArray()得到原來數組;先判斷指定的下標是否越界或不規范,如果不符合則拋出下標越界的異常,如果符合;再判斷該元素移動多少個元素,如果發現移動0個元素那么證明要添加的元素應為數組的尾部,那么直接與添加元素的原理相同,如果不等于0那么證明該元素被添加在數組的中間某個位置,則通過System.arraycopy(elements, 0, newElements, 0, index)方法將該下標之前的元素復制出來至新數組、再通過System.arraycopy(elements, index, newElements, index + 1,numMoved)將該下標后半部分元素復制至新數組,再將元素添加至該下標;最后將新數組放回并釋放鎖
ArrayList的add()方法
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
CopyOnWriteArrayList的add()方法
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 {
newElements = new Object[len + 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}
4.Remove()方法
通過getArray()得到原來數組;獲取到指定下標的元素、先判斷刪除的元素是否為數組中最后一個元素,如果是數組中最后一個元素則直接復制len-1個元素至新數組再將新數組放回,如果不是最后一個通過 System.arraycopy(elements, 0, newElements, 0, index)方法將刪除元素下標之前的元素復制至新數組再通過System.arraycopy(elements, index + 1, newElements, index, numMoved)方法將刪除元素下標之后的元素復制至新數組;最后將新數組放回并釋放鎖
ArrayList的remove()
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
CopyOnWriteArrayList的add()方法
public E remove(int index) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index);
int numMoved = len - index - 1;
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
總結
- 多線程并發時,ArrayList是線程不安全,而CopyOnWriteArrayList是線程安全就是因為CopyOnWriteArrayList實現ReentrantLock鎖機制,也正因為鎖機制CopyOnWriteArrayList的速度沒有ArrayList的速度快。
- ArrayList是會進行擴容,CopyOnWriteArrayList每次都是復制數組無需擴容,但大量的數組復制也是很消耗內存及cpu的性能。
- CopyOnWriteArrayList由于只在寫時加鎖,讀時無鎖,導致多線程讀數據時數據并一定是最新的數據,導致數據無法做到實時性,也常用于寫少讀多的場景。
- 還有一些方法都類似與上面的原理,自己可以找找源代碼再查看。
原文鏈接:https://blog.csdn.net/qq_55135629/article/details/126922390
- 上一篇:TCP協議和UDP協議
- 下一篇:創建的對象如何在堆區分配內存
相關推薦
- 2022-06-14 C語言?分析逆序字符串與字符串的逆序輸出有什么區別_C 語言
- 2023-03-01 pyinstaller打包后偶爾出現黑窗口一閃而過的問題及解決_python
- 2022-06-12 .Net?Core?3.1?Web?API基礎知識詳解(收藏)_實用技巧
- 2022-07-18 實現?Python?腳本生成命令行_python
- 2022-05-11 django配置DJANGO_SETTINGS_MODULE的實現_python
- 2022-07-22 springboot項目整合配置knife4j
- 2022-05-21 Python中三種花式打印的示例詳解_python
- 2022-05-06 Python如何判斷字符串是否僅包含數字_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支