初识CopyOnWriteArrayList
第一次见到CopyOnWriteArrayList,是在研究JDBC的时候,每一个数据库的Driver都是维护在一个CopyOnWriteArrayList中的,为了证明这一点,贴两段代码,第一段在com.mysql.jdbc.Driver下,也就是我们写Class.forName(“…”)中的内容:
public class Driver extends NonRegisteringDriver implements java.sql.Driver { public Driver() throws SQLException { } static { try { DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } }
看到com.mysql.jdbc.Driver挪用了DriverManager的registerDriver要领,这个类在java.sql.DriverManager下:
public class DriverManager { private static final CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList(); private static volatile int loginTimeout = 0; private static volatile PrintWriter logWriter = null; private static volatile PrintStream logStream = null; private static final Object logSync = new Object(); static final SQLPermission SET_LOG_PERMISSION = new SQLPermission("setLog"); ... }
看到所有的DriverInfo都在CopyOnWriteArrayList中。既然看到了CopyOnWriteArrayList,我自然免不了要研究一番为什么JDK利用的是这个List。
首先提两点:
1、CopyOnWriteArrayList位于java.util.concurrent包下,可想而知,图纸加密,这个类是为并发而设计的
2、CopyOnWriteArrayList,顾名思义,Write的时候老是要Copy,也就是说对付CopyOnWriteArrayList,任何可变的操纵(add、set、remove等等)都是陪伴复制这个行动的,后头会解读CopyOnWriteArrayList的底层实现机制
四个存眷点在CopyOnWriteArrayList上的谜底
如何向CopyOnWriteArrayList中添加元素
对付CopyOnWriteArrayList来说,增加、删除、修改、插入的道理都是一样的,所以用增加元素来阐明一下CopyOnWriteArrayList的底层实现机制就可以了。先看一段代码:
public static void main(String[] args) { List<Integer> list = new CopyOnWriteArrayList<Integer>(); list.add(1); list.add(2); }
看一下这段代码做了什么,先是第3行的实例化一个新的CopyOnWriteArrayList:
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8673264195747942595L; /** The lock protecting all mutators */ transient final ReentrantLock lock = new ReentrantLock(); /** The array, accessed only via getArray/setArray. */ private volatile transient Object[] array; ... }
public CopyOnWriteArrayList() { setArray(new Object[0]); }
final void setArray(Object[] a) { array = a; }
看到,对付CopyOnWriteArrayList来说,底层就是一个Object[] array,然后实例化一个CopyOnWriteArrayList,用图来暗示很是简朴:
就是这样,Object array指向一个数组巨细为0的数组。接着看一下,第4行的add一个整数1做了什么,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(); } }
画一张图暗示一下:
每一步都清楚地暗示在图上了,软件开发,一次add大抵经验了几个步调:
1、加锁
2、拿到原数组,获得新数组的巨细(原数组巨细+1),实例化出一个新的数组来
3、把原数组的元素复制到新数组中去
4、新数组最后一个位置配置为待添加的元素(因为新数组的巨细是凭据原数组巨细+1来的)
5、把Object array引用指向新数组
6、解锁
整个进程看起来较量像ArrayList的扩容。有了这个基本,我们再来看一下第5行的add了一个整数2做了什么,这应该很是简朴了,照旧画一张图来暗示:
和前面差不多,就不表明白。