Collections.synchronizedList
- Collections.synchronizedList 包装
- 使用分析
- 优点
- 线程安全,synchronized 方法内代码级别加锁
- 缺点
- 性能问题:方法级别加synchronized锁
- 复合操作非线程安全:但对于复合操作(如先检查列表是否包含某个元素,然后再添加该元素),Collections.synchronizedList 并不能保证其线程安全。需要开发者手动进行同步控制
- 迭代器非线程安全:返回的列表的迭代器不是线程安全的。在使用迭代器遍历列表时,如果其他线程同时对列表进行修改,会抛出 ConcurrentModificationException 异常因此,在迭代过程中需要手动进行同步
- 适用场景:
- 对现有代码的改造
- 如果项目中已经存在大量使用非线程安全 List 的代码,并且需要将其改为线程安全的,可以使用 Collections.synchronizedList 进行快速改造,而无需对代码结构进行大规模调整
- 简单的线程安全需求
- 当只需要对单个操作进行线程安全控制,且不涉及复合操作和复杂的并发场景时,
- 对现有代码的改造
- 优点
- 设计分析
- 设计目标
- 将一个非线程安全的 List 转换为线程安全的 List
- 设计思路
- 解决问题的思路
- 使用装饰设计模式,将被装饰的list的增删改查调用前增加synchronized代码块锁
- 解决问题的思路
- 实现原理
- 使用装饰设计模式,将被装饰的list的增删改查调用前增加synchronized代码块锁,锁对象是SynchronizedList实例
- 设计目标
- 源码分析
- 继承关系
- class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E>
- class SynchronizedList<E>
- 构造方法
- static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
//final属性的list
final List<E> list;
SynchronizedList(List<E> list) {
// 调用父类SynchronizedCollection的构造方法
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
- static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {
- synchronized锁对象mutex
- 构造方法没有传入锁对象,则默认为mutex=this
- 构造方法传入锁对象A,则为mutex=A
- 操作方法使用synchronized代码块锁对象为mutex
- // 注意:synchronizedList是用同步代码块给传入的集合对象加锁!
// 可以看到所有的操作都是上了锁的,synchronized (mutex),锁对象是mutex是来自SynchronizedCollection父类
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);}
}
- // 注意:synchronizedList是用同步代码块给传入的集合对象加锁!
- 迭代器没有synchronized需要自己实现线程安全控制
- // 但是有一个地方很值得注意的是迭代器的使用是没有上锁的,而且源码是标注了
// 需要用户去自己做同步处理, 迭代器,分割,流操作都需要自己实现同步处理。
public ListIterator<E> listIterator() {
return list.listIterator(); // Must be manually synched by user
}
public ListIterator<E> listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user
} - 转换包装后的list可以实现add,remove,get等操作的线程安全性,但是对于迭代操作,Collections.synchronizedList并没有提供相关机制,所以迭代时需要对包装后的list(必须对包装后的list进行加锁,锁其他的不行)进行手动加锁。
List list = Collections.synchronizedList(new ArrayList());
//必须对list进行加锁
synchronized (list) {
Iterator i = list.iterator();
while (i.hasNext())
foo(i.next());
}
迭代操作必须加锁,可以使用synchronized关键字修饰;
synchronized持有的监视器对象必须是synchronized (list),即包装后的list,使用其他对象如synchronized (new Object())会使add,remove等方法与迭代方法使用的锁不一致,无法实现完全的线程安全性。
- // 但是有一个地方很值得注意的是迭代器的使用是没有上锁的,而且源码是标注了
- https://blog.csdn.net/weixin_45480785/article/details/118934849
- 继承关系
- 使用分析
作者: 一点点征服
出处:http://www.cnblogs.com/ldq2016/
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利