java.lang.NullPointerException
函数线程是否安全?多个线程会在列表上正确循环吗?
compute()
答案 0 :(得分:1)
考虑到数据没有变异(正如你在评论中提到的那样),不会有任何脏/幻读。
答案 1 :(得分:1)
如果列表是专门为该方法创建的,那么您就可以了。也就是说,如果任何其他方法或类中的列表未被修改,那么该代码是线程安全的,因为您只是在阅读。< / p>
如果您不确定参数是否来自可信赖的来源(即使您确定),则一般建议是制作该集合的只读副本。
this.list = Collections.unmodifiableList(new ArrayList<Integer>(list));
但请注意,列表的元素也必须是线程安全的。如果在您的实际场景中,列表包含一些可变结构,而不是 Integer (它们是不可变的),您应该确保对元素的任何修改都是线程安全的。
答案 2 :(得分:0)
此版本
class Foo {
private final List<Integer> list;
public Foo(List<Integer> list) {
this.list = new ArrayList<>(list);
}
public void compute() {
for(Integer i: list) {
// ...
}
}
}
是线程安全的,如果以下成立:
list
arc to ctor无法在ctor运行时修改(例如,它是调用者中的局部变量)或线程安全本身(例如CopyOnWriteArrayList
); compute
无法修改list
内容(正如OP所述)。我猜compute
应该不是void
,而是返回一些数值,是任何效用...... 答案 3 :(得分:0)
cocncurent library中有线程安全列表。如果您想要线程安全的集合,请始终使用它。线程安全列表为 CopyOnWriteArrayList
答案 4 :(得分:0)
如果您可以保证列表在其他地方没有被修改,而您正在迭代该代码是线程安全的。
我会创建一个列表的只读副本,但绝对确定它不会在别处修改:
class Foo {
private List<Integer> list;
public Foo(List<Integer> list) {
this.list = Collections.unmodifiableList(new ArrayList<>(list));
}
public void compute() {
for (Integer i: list) {
// do some thing with it
// NO LIST modifications
}
}
}
如果您不介意为项目添加依赖项,我建议您使用Guava&#39; ImmutableList:
this.list = ImmutableList.copyOf(list);
使用Guavas不可变集合也是一个好主意,只要您使用的集合不会发生变化,因为它们本身就是不可变的线程安全。
答案 5 :(得分:0)
例如,在拥有2个线程时,您可以轻松检查行为:
public class Test {
public static void main(String[] args) {
Runnable task1 = () -> { new Foo().compute(); };
Runnable task2 = () -> { new Foo().compute(); };
new Thread(task1).start();
new Thread(task2).start();
}
}
如果保证列表不会在其他任何地方更改,则迭代它是线程安全的,如果您实现compute
只是打印列表内容,调试代码应该有助于您理解它是< / em>线程安全。