设为首页 加入收藏

TOP

Java并发包——线程安全的Collection相关类(二)
2019-09-03 00:51:17 】 浏览:44
Tags:Java 发包 线程 安全 Collection 相关
;Index: "+index+", Size: "+len); 12 Object[] newElements; 13 // 如果插入位置是末尾。 14 int numMoved = len - index; 15 if (numMoved == 0) 16 // 将原数组进行拷贝并扩大一个容量。 17 newElements = Arrays.copyOf(elements, len + 1); 18 else { 19 // 如果不是插入到末尾,则创建扩大一个容量的数组。 20 newElements = new Object[len + 1]; 21 // 分段复制原数组,并空出指定位置。 22 System.arraycopy(elements, 0, newElements, 0, index); 23 System.arraycopy(elements, index, newElements, index + 1, numMoved); 24 } 25 // 设置指定位置的指定元素。 26 newElements[index] = element; 27 // 将array引用的地址指向新的数组。 28 setArray(newElements); 29 } finally { 30 lock.unlock(); 31 } 32 }

删除元素

删除元素就是将array数组中指定位置的元素删除。

它的实现方式是,如果被删除的是最后一个元素,则直接通过Arrays.copyOf()进行处理,而不需要新建数组。否则,新建数组,然后将array数组中被删除元素之外的其它元素拷贝到新数组中。最后,将新数组赋值给array数组。

 1 public E remove(int index) {
 2     // 使用锁来保证线程安全。
 3     final ReentrantLock lock = this.lock;
 4     lock.lock();
 5     try {
 6         // 获得array指向的引用地址。
 7         Object[] elements = getArray();
 8         int len = elements.length;
 9         // 根据指定的位置获取元素。
10         E oldValue = get(elements, index);
11         // 如果指定的元素是最后一个元素。
12         int numMoved = len - index - 1;
13         if (numMoved == 0)
14             // 将原数组进行拷贝截取并将array的引用地址指向新的数组。
15             setArray(Arrays.copyOf(elements, len - 1));
16         else {
17             // 如果不是最后一个元素,则创建减少一个容量的数组。
18             Object[] newElements = new Object[len - 1];
19             // 分段复制原数组,并空出指定位置。
20             System.arraycopy(elements, 0, newElements, 0, index);
21             System.arraycopy(elements, index + 1, newElements, index, numMoved);
22             // 将array的引用地址指向新的数组。
23             setArray(newElements);
24         }
25         // 返回该位置上的元素。
26         return oldValue;
27     } finally {
28         lock.unlock();
29     }
30 }

获取元素

获取元素很简单,就是返回array数组的指定位置的元素。

1 public E get(int index) {
2     return get(getArray(), index);
3 }
4 
5 private E get(Object[] a, int index) {
6     return (E) a[index];
7 }

设置元素

在设置元素之前判断指定位置的旧元素是否和新元素相等,如果相等则不进行替换,但仍然要调用setArray()方法。

 1 public E set(int index, E element) {
 2     // 使用锁来保证线程安全。
 3     final ReentrantLock lock = this.lock;
 4     lock.lock();
 5     try {
 6         // 获得array指向的引用地址。
 7         Object[] elements = getArray();
 8         // 获取指定位置的旧元素。
 9         E oldValue = get(elements, index);
10         // 如果旧元素的引用和新元素的引用不同。
11         if (oldValue != element) {
12             // 创建新的数组并拷贝array数组的值,替换新数组指定位置的元素。
13             int len = elements.length;
14             Object[] newElements = Arrays.copyOf(elements, len);
15             newElements[index] = element;
16             // 将array的引用地址指向新的数组
17             setArray(newElements);
18         } else {
19             // 为了确保voliatile的语义,任何一个读操作都应该是写操作的结构,所以尽管写操作没有改变数据,还是调用set方法,当然这仅仅是语义的说明,去掉也是可以的。
20             setArray(elements);
21         }
22         return oldValue;
23     } finally {
24         lock.unlock();
25     }
26 }

遍历

CopyOnWriteArrayList类的迭代方法返回的是一个COWIterator类的对象。

1 public Iterator<E> iterator() {
2     return new COWIterator<E>(getArray(), 0);
3 }

CopyOnWriteArrayList在类里维护了一个用于遍历的COWIterator类,COWIterator类实现了ListIterator接口。

 1 static final class COWIterator<E> implements ListIterator<E> {
 2     // 数组的快照。
 3     private final Object[] snapshot;
 4     // 指定下标。
 5     private int cursor;
 6 
 7     // 构造方法。
 8     private COWIterator(Object[] elements, int initialCursor) {
 9         cursor = initialCursor;
10         snapshot = elements;
11     }
12 
13     // 判断是否存在下一个元素。
14     public boolean hasNext() {
15         return cursor < snapshot.length;
16     }
17 
18     // 判断是否存在上一个元素。
19     public boolean hasPrevious() {
20         return cursor > 0;
21     }
22 
23     // 获取下一个元素。
24     @SuppressWarnings("unchecked"
首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇消息中间件介绍(非原创) 下一篇RabbitMQ 消费端限流、TTL、死信..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目