1、关于Collections.synchronizedList线程不安全的部分
1.1 构造
使用Collections.synchronizedList修饰后的list也有一些部分是不安全的。
//这句话其实是产生一个新的对象,
List list = Collections.synchronizedList(new ArrayList());
//来看看这个函数
public class Collections {
//上面省略了很多源码....
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
//省略源码....
}
1.2 这里有两个内部类,SynchronizedRandomAccessList和SynchronizedList
SynchronizedRandomAccessList实现了RandomAccess接口,
下面我们来看SynchronizedList;
/**
* @serial include
*/
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
//可以看到所有的操作都是上了锁的,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);}
}
//省略...
}
*
1.3 没有做同步的地方
但是有一个地方很值得注意的是迭代器的使用是没有上锁的,而且源码是标注了,需要用户去自己做同步处理, 迭代器,分割,流操作都需要自己实现同步处理。
*
SynchronizedCollection:
static class SynchronizedCollection<E> implements Collection<E>, Serializable {
private static final long serialVersionUID = 3053995032091335093L;
final Collection<E> c; // Backing Collection
final Object mutex; // Object on which to synchronize
//省略了做了同步的操作和一些源码......
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!需要用户手动的去实现同步
}
@Override
public Spliterator<E> spliterator() {
return c.spliterator(); // Must be manually synched by user!需要用户手动的去实现同步
}
@Override
public Stream<E> stream() {
return c.stream(); // Must be manually synched by user!需要用户手动的去实现同步
}
@Override
public Stream<E> parallelStream() {
return c.parallelStream(); // Must be manually synched by user!需要用户手动的去实现同步
}
private void writeObject(ObjectOutputStream s) throws IOException {
synchronized (mutex) {s.defaultWriteObject();}
}
//省略了做了同步的操作......
}