前两天面试遇到的问题,arrayList本身是线程不安全的,但是他的查询快,因为底层是数组,根据下标找很方便,我们想用他的性能,又想保证安全性该怎么处理?
解决方案如下:
方案一: 通过collections.synchronizedList方法将ArrayList转化为线程安全的,相关源码如下:
其中,涉及到get、set、add、remove,indexOf、lastIndexOf,addAll等方法都添加了同步锁synchronized,另外上图中最后一行代码的注解还在告知我们,类似Iterator方法等无法保证线程安全。效率也并不好,感觉跟vector没什么区别。
方案二:
通过CopyOnWriteArrayList方法封装ArrayList
见名知意 通过复制写的操作来进行处理,可以理解为数据库的读写分离 ,对查询get操作不进行加锁处理,对修改,新增方法添加锁
参考源码如下
第一部分:先定义出数组,之后在增删操作的时候对数组进行扩展
第二部分,以add为例,查看处理逻辑
在进行add的时候,分为在数组的最末端添加和指定下标的添加方法
最末端添加的时候,将原数组的长度+1,直接复制返回。
指定下标添加的时候,判断是否为最末端,不是最末端的话将数组通过当前下标分为两部分,前半部分先转换,后半部分将新的元素塞进去,然后返回,并且在方法的开始和结束都有lock锁的处理
之后我们看看查询方法:
并未加锁。
在copyOnWrite方法中,我们在查询时的性能,效率一定比方案一好,当然,在进行修改操作的时候并效率其实是一样的。
在开发中并没有十全十美的方法能在保证性能的情况下保证安全,我们只能尽量保证利益最大化, 另外我在方案二中的开头有专门把array这个数组给截出来,是希望自己记住,多线程处理的情况下,共享数据最好添加一个volatitle和transient来保证数据的可见性和安全性。