专栏名称: 老马说编程
从入门到高级, 深入浅出, 老马和你一起探索编程及计算机技术的本质, 篇篇原创, 用心写作。
目录
相关文章推荐
码农翻身  ·  今年后端这薪资是认真的吗? ·  昨天  
阿里云云栖号  ·  一周AI大事件 ·  昨天  
稀土掘金技术社区  ·  做了个渐变边框的input输入框,领导和客户 ... ·  4 天前  
程序猿  ·  Python有史以来最强大的挑战者终于出现 ·  3 天前  
51好读  ›  专栏  ›  老马说编程

(73) 并发容器 - 写时拷贝的List和Set / 计算机程序的思维逻辑

老马说编程  · 公众号  · 程序员  · 2017-02-17 22:06

正文

请到「今天看啥」查看全文


;
startIteratorThread(list);
startModifyThread(list);
}


不过,需要说明的是, CopyOnWriteArrayList的迭代器不支持修改操作,也不支持一些依赖迭代器修改方法的操作,比如Collections的sort方法 ,看个例子:

public static void sort(){
CopyOnWriteArrayList list = new CopyOnWriteArrayList();
list.add("c");
list.add("a");
list.add("b");
Collections.sort(list);
}


执行这段代码会抛出异常:

Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.concurrent.CopyOnWriteArrayList$COWIterator.set(CopyOnWriteArrayList.java:1049)
at java.util.Collections.sort(Collections.java:159)


为什么呢?因为Collections.sort方法依赖迭代器的set方法,其代码为:

public static > void sort(List list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator i = list.listIterator();
for (int j=0; j i.next();
i.set((T)a[j]) ;
}
}


基于synchronized的同步容器的另一个问题是复合操作,比如先检查再更新,也需要调用方加锁,而CopyOnWriteArrayList直接支持两个原子方法:

//不存在才添加,如果添加了,返回true,否则返回false
public boolean addIfAbsent(E e)
//批量添加c中的非重复元素,不存在才添加,返回实际添加的个数
public int addAllAbsent(Collection extends E> c)


基本原理
CopyOnWriteArrayList的内部也是一个数组,但这个数组是以原子方式被整体更新的。每次修改操作,都会新建一个数组,复制原数组的内容到新数组,在新数组上进行需要的修改,然后以原子方式设置内部的数组引用,这就是写时拷贝。


所有的读操作,都是先拿到当前引用的数组,然后直接访问该数组,在读的过程中,可能内部的数组引用已经被修改了,但不会影响读操作,它依旧访问原数组内容。


换句话说,数组内容是只读的,写操作都是通过新建数组,然后原子性的修改数组引用来实现的。我们通过代码具体来看下。

内部数组声明为:







请到「今天看啥」查看全文