我们在使用ArrayList
的时候,经常被并发的问题所困扰,这个时候我们通常会去找一个线程安全的列表,例如我们熟知的SynchronizedList
、CopyOnWriteArrayList
、Vector
等
SynchronizedList
SynchronizedList
通过synchronized
关键字来保证变更过程是同步执行的
java
static class SynchronizedList<E> extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return list.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return list.hashCode();}
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
public int indexOf(Object o) {
synchronized (mutex) {return list.indexOf(o);}
}
public int lastIndexOf(Object o) {
synchronized (mutex) {return list.lastIndexOf(o);}
}
public boolean addAll(int index, Collection<? extends E> c) {
synchronized (mutex) {return list.addAll(index, c);}
}
2、CopyOnWriteArrayList
CopyOnWriteArrayList
是java.util.concurrent
包中的一个线程安全列表实现。它通过在每次修改时创建底层数组的新副本来确保线程安全。这种实现适用于读多写少的场景,因为写操作的开销较大,而读操作则无需加锁。 这是CopyOnWriteArrayList
的set方法源码
java
/**
* 替换列表中指定位置的元素
*
* @param index 要替换的元素索引
* @param element 要存储的新元素
* @return 被替换的旧元素
*/
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 {
// 即使值相同也要调用setArray
// 这确保了volatile写入语义,维护了内存可见性
setArray(elements);
}
// 返回被替换的旧值
return oldValue;
} finally {
// 无论操作是否成功,都释放锁
lock.unlock();
}
}
3、Vector
Vector
是Java早期提供的一种线程安全的列表实现,所有操作都加锁。由于所有操作都进行了同步,Vector
的性能在现代应用中通常不如其他更轻量级的同步策略。
ImmutableList的特点是什么以及为什么要选择它
ImmutableList
是Guava库中的一个不可变集合类,它是java.util.List
接口的不可变实现,实现简单可靠。正如名称所示,一旦创建,ImmutableList
的元素无法被改变。这种设计使得它在多线程环境下尤其有用,可以像String
一样安全地被共享。
ImmutableList是如何保证里面的元素是不可变的
ImmutableList
(以Guava库中的实现为例)通过多种机制确保其不可变性:
禁止修改操作
所有修改集合的方法(如add
、remove
、set
等)都会抛出UnsupportedOperationException
内部数据结构保护
内部数组是private final
的 没有提供修改内部状态的方法
防御性复制
创建时对输入集合进行复制,而不是引用 返回内部元素时进行保护性处理
不可变视图
返回的子列表、迭代器等都是不可变的
但是需要注意的是ImmutableList
只能保证列表结构不可变,不能保证列表中对象的内部状态不变。如果列表包含可变对象,这些对象的内部状态仍可被修改。
最后简单看一下ImmutableList的源码
java
ImmutableList.java
/**
* 将对象数组转换为不可变列表
*
* @param elements 源数组
* @param length 要使用的元素数量
* @return 包含指定元素的不可变列表
*/
static <E> ImmutableList<E> asImmutableList(Object[] elements, int length) {
switch (length) {
case 0:
// 空列表情况
return of();
case 1:
// 单元素列表使用专门的实现以提高效率
@SuppressWarnings("unchecked") // collection had only Es in it
ImmutableList<E> list = new SingletonImmutableList<E>((E) elements[0]);
return list;
default:
// 如果指定长度小于数组实际长度,创建一个新数组
if (length < elements.length) {
elements = arraysCopyOf(elements, length);
}
// 创建标准不可变列表
return new RegularImmutableList<E>(elements);
}
}
/**
* 返回从指定位置开始的不可修改列表迭代器
*/
@Override
public UnmodifiableListIterator<E> listIterator(int index) {
return new AbstractIndexedListIterator<E>(size(), index) {
@Override
protected E get(int index) {
return ImmutableList.this.get(index);
}
};
}
/**
* 查找指定对象在列表中第一次出现的索引
* 如果对象为null或不存在则返回-1
*/
@Override
public int indexOf(@Nullable Object object) {
return (object == null) ? -1 : Lists.indexOfImpl(this, object);
}
/**
* 查找指定对象在列表中最后一次出现的索引
* 如果对象为null或不存在则返回-1
*/
@Override
public int lastIndexOf(@Nullable Object object) {
return (object == null) ? -1 : Lists.lastIndexOfImpl(this, object);
}
/**
* 检查列表是否包含指定对象
*/
@Override
public boolean contains(@Nullable Object object) {
return indexOf(object) >= 0;
}
/**
* 返回指定范围内元素的不可变列表视图
* 从fromIndex(包含)到toIndex(不包含)
* 如果fromIndex和toIndex相等,则返回空列表
*/
@Override
public ImmutableList<E> subList(int fromIndex, int toIndex) {
// 检查索引范围是否有效
checkPositionIndexes(fromIndex, toIndex, size());
int length = toIndex - fromIndex;
if (length == size()) {
// 如果范围覆盖整个列表,直接返回this
return this;
}
switch (length) {
case 0:
// 空子列表
return of();
case 1:
// 单元素子列表
return of(get(fromIndex));
default:
// 多元素子列表
return subListUnchecked(fromIndex, toIndex);
}
}
/**
* 由subList方法在toIndex-fromIndex>1时调用
* 此时索引验证已经完成
*/
ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
return new SubList(fromIndex, toIndex - fromIndex);
}
/**
* 子列表实现,作为原列表的视图
*/
class SubList extends ImmutableList<E> {
// 在原列表中的偏移量
final transient int offset;
// 子列表的长度
final transient int length;
SubList(int offset, int length) {
this.offset = offset;
this.length = length;
}
@Override
public int size() {
return length;
}
@Override
public E get(int index) {
// 检查索引是否在范围内
checkElementIndex(index, length);
// 转换为原列表中的索引并获取元素
return ImmutableList.this.get(index + offset);
}
@Override
public ImmutableList<E> subList(int fromIndex, int toIndex) {
// 检查索引范围是否有效
checkPositionIndexes(fromIndex, toIndex, length);
// 转换为原列表的索引并创建子列表
return ImmutableList.this.subList(fromIndex + offset, toIndex + offset);
}
@Override
boolean isPartialView() {
// 子列表总是部分视图
return true;
}
}
/**
* 不支持的操作 - 在指定位置添加集合元素
* 保证抛出异常并保持列表不变
*
* @throws UnsupportedOperationException 总是抛出
* @deprecated 不支持的操作
*/
@CanIgnoreReturnValue
@Deprecated
@Override
public final boolean addAll(int index, Collection<? extends E> newElements) {
throw new UnsupportedOperationException();
}
/**
* 不支持的操作 - 替换指定位置的元素
* 保证抛出异常并保持列表不变
*
* @throws UnsupportedOperationException 总是抛出
* @deprecated 不支持的操作
*/
@CanIgnoreReturnValue
@Deprecated
@Override
public final E set(int index, E element) {
throw new UnsupportedOperationException();
}
/**
* 不支持的操作 - 在指定位置插入元素
* 保证抛出异常并保持列表不变
*
* @throws UnsupportedOperationException 总是抛出
* @deprecated 不支持的操作
*/
@Deprecated
@Override
public final void add(int index, E element) {
throw new UnsupportedOperationException();
}
/**
* 不支持的操作 - 移除指定位置的元素
* 保证抛出异常并保持列表不变
*
* @throws UnsupportedOperationException 总是抛出
* @deprecated 不支持的操作
*/
@CanIgnoreReturnValue
@Deprecated
@Override
public final E remove(int index) {
throw new UnsupportedOperationException();
}