当我们这个资源不可变的时候,无论多线程还是单线程是无所谓的。
如何不可变呢?类 final,参数 final ,,没有参数修改的地方。比如 String。你就是想破坏都是不可能的。很硬核吧。
但是在我们真正编程的时候,这种情景貌似不太多啊,其实也是挺多的。比如我们可能会用 CopyOnWriteArrayList 在进行多线程编程的时候,会使用它来规避多线程问题。那么它的原理是什么呢?
CopyOnWriteArrayList 采用 copy-on-write 技术来避免读写冲突的,翻译过来就是写时赋值。也就是在对集合进行 写 操作的时候,会保证这个集合已经被复制一份了,在新的复制里进行数据的修改,最后在替换原集合。保证读的时候还是之前的原数据,不会担心取元素的时候元素被修改了。不过说真的,这个方法也是简单粗暴,如果写多读少,很显然不太合适,更适合写少读多的情景。那么写多的情景怎么办呢?
这就用到了另一个方法了。
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
通过源码我们知道这个方法其实也是简单粗暴,就是 List 的一个包装类,里面所有的方法几乎都加了 synchronized (ps:listIterator 等遍历方法并没有加synchronized 所以我们需要手动加锁处理遍历 ),真的很粗暴,这样的情况下 写多倒是性能提升了,但是读的性能就相对差一点了,所以一定要根据自己的实际情况来选择合适的安全容器。
可能很多人就要说 Vector 不是线程安全的吗?为啥不用 Vector ?虽然是线程安全的,但是性能确实不咋好,特别是 Vector 是本质数组,拓展大小需要复制这就很蛋疼了,List 本质是链表,这就决定了 Vector 更适合数据变化少,对象简单,随机访问频繁的场景。而 List 适合数据变化量大,对象复杂,插入和删除频繁的。所以如果是多非常多,写很少,对象很简单,数据量很小,那么 Vector 非常适合。读写都差不多就是 synchronizedList ,读多写少,对象复杂那就是 CopyOnWriteArrayList。
源码实例在 immutable 中,synchronizedList 的小栗子。
