Java 我必须在流读取的列表上进行同步吗?
如果我有一个线程敏感列表,我在迭代时通常会这样做:Java 我必须在流读取的列表上进行同步吗?,java,java-8,java-stream,Java,Java 8,Java Stream,如果我有一个线程敏感列表,我在迭代时通常会这样做: List list = Collections.synchronizedList(new ArrayList()); ... synchronized(list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); } 我想知道我是否使用list.st
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
我想知道我是否使用list.stream(),然后在流上执行一些操作,如过滤器等,如果我还必须将列表放入同步块中,或者流是否复制了列表
感谢流操作在内部使用
spliterator()
方法
以下是ArrayList
中的spliterator()
方法:
public Spliterator<E> spliterator() {
checkForComodification();
return new ArrayListSpliterator<E>(ArrayList.this, offset,
offset + this.size, this.modCount);
}
这与迭代器()中的注释类似:
流可以看作是原始数据的“视图”。这意味着:避免复制是他们天性的一部分
只有排序等操作需要创建输入的副本。因此:当您的输入可以被另一个线程更改时,您需要对此进行保护 是的,使用流时必须同步对列表的访问,就像不使用流时一样。同步应由用户负责 流本身并不保证创建原始序列的任何副本。它可以在某些中间计算(例如,
排序
)期间复制,但您不应依赖于此。对于流的每一次使用,这样做都是对资源的浪费
例如,如果用户希望流在副本上运行,他们必须手动创建副本或使用CopyOnWriteArrayList
而不是ArrayList
此外,请记住这一点。在执行终端操作(例如,collect
,forEach
)之前,不会访问底层序列
public Spliterator<E> spliterator() {
return c.spliterator(); // Must be manually synched by user!
}
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
public Stream<E> stream() {
return c.stream(); // Must be manually synched by user!
}