我认为这可能是一件简单的事情,但想知道是否有这种模式或优雅的方式。我看了一眼 Guava 。 我有一个类级别列表,一个在调度程序上引用此 listOfObjects 的方法,以及一个在调度程序上更新它的方法。 updater 方法收集应在此列表中的所有对象,并准备好一个新列表来重新初始化 listOfObjects。但是,即使引用它的方法正在使用它,我是否应该设置它,或者是否有更安全的方法来执行此操作。
private List<Object> listOfObjects = new ArrayList<Object>();
@Scheduled
public referToList(){
for(Object o : listOfObjects){
doSomething(o);
}
}
@Scheduled
public updateList(){
List<Object> tempList = new ArrayList<Object>();
tempList = doSomethingToPopulateList();
this.listOfObjects = tempList;
}
因此,当referToList处于迭代过程中时,其可能的updateList可以是更新列表。我也可以在referToList中创建一个临时列表,因此它可以在listOfObjects的副本上工作,但不确定其效率如何
最佳答案
tl;dr - 您的代码是安全的,但可以使 future 的错误更具弹性。
首先,虽然不是立即必要的,但您应该倾向于选择不可变集合而不是可变集合,特别是在处理并发时。这样做是一个很好的做法,这样可以防止不必要的修改,并且可以更轻松地推断列表的状态。您的代码现在没有被破坏,如果其他线程在迭代时直接修改了 listOfObjects
,那么它就会被破坏,因此使其不可变可以防止这种情况发生。
换句话说,当分配给 listOfObjects
时,用 Collections.unmodifableList(tempList)
或 Guava 的 ImmutableList.copyOf(tempList)
包装列表(区别在于 Guava 的 ImmutableList 实际上创建了列表项的副本,而 unmodifableList 只是创建了一个不可变 View - 这意味着对基础列表的更改仍然会出现)。或者只是从 doSomethingToPopulateList()
返回一个不可变列表。
但是要回答您的问题,您正确的做法是不直接修改它,而是在将新列表收集到 tempList
中时更新 listOfObjects
。即使 referToList()
当前正在执行,这也不会导致问题。这是因为 listOfObjects
是一个引用。当你运行时
for(Object o : listOfObjects){
doSomething(o);
}
JVM 在 for 循环开始时获取 listOfObjects
所引用的内存引用,并迭代该内存空间中的项目。当迭代发生时,您的其他代码可以更新 listOfObjects
所指向的内存引用(通过在 updateList()
中重新分配它),但这不会影响进度运行 for 循环的过程。
关于java - 更新调度程序上的 Activity 集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38385278/