前面介绍的ArrayList和LinkedList, 在多线程的场景中就不适合了。JDK提供了线程安全的List。
Vector和CopyOnWriteArrayList是线程安全的
1、Vector
这个类属性和方法同ArrayList,主要区别是Vector在其主要方法上都加上了synchronized关键字,这样就达到了线程安全的目的。
2、CopyOnWriteArrayList源码分析
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
final transient ReentrantLock lock = new ReentrantLock();
//使用数组存储数据
private transient volatile Object[] array;
}
相对于ArrayList,多了一个用于线程安全的lock,少了计数size
3、CopyOnWriteArrayList构造函数
//1、空构造函数
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
//2、集合构造函数
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] elements;
if (c.getClass() == CopyOnWriteArrayList.class)
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
elements = c.toArray();
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
//赋值给当前array
setArray(elements);
}
//3、数字构造函数
public CopyOnWriteArrayList(E[] toCopyIn) {
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
//setArray方法
final void setArray(Object[] a) {
array = a;
}
主要是将参数解析为一个数字对象,然后复制给array
4、添加操作
//1、添加单个元素
public boolean add(E e) {
}
//2、添加单个元素到某个位置
public void add(int index, E element) {
}
//3、添加集合元素
public boolean addAll(Collection<? extends E> c){
}
//4、添加集合从某个位置开始
public boolean addAll(int index, Collection<? extends E> c) {
主要分析下public boolean add(E e)
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//1、获取锁对象
lock.lock();
try {
//2、增加元素
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
//3、释放锁
lock.unlock();
}
}
需要注意的是:CopyOnWriteArrayList并没有ArrayList的自动扩容(1.5倍),添加了一次执行Arrays.copyOf操作,这个会成为性能瓶颈
5、删除操作
我们主要看下
public E remove(int index) {
final ReentrantLock lock = this.lock;
//1、获取锁
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index);
int numMoved = len - index - 1;
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
6、修改操作
我们看下
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
//直接获取元素,并替换
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
7、查询操作
private E get(Object[] a, int index) {
return (E) a[index];
}
public E get(int index) {
return get(getArray(), index);
}
这里的get不是线程安全的。
而Vector的查询操作,synchronized 修饰,是线程安全的。
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
总结: 在Vector中,无论增删操作,还是查询操作,统统都加上synchronized锁,
而在CopyOnWriteArrayList中,只有增删改操作添加了锁,查询则没有,使多线程能并行访问。
来源:oschina
链接:https://my.oschina.net/u/4261498/blog/3220193