我认为这可能是一件容易的事,但想知道是否有这种方式或优雅的方式。我看了番石榴。
我有一个类级别的List,一个在调度程序上引用此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-您的代码是安全的,但可以使其对将来的错误更具弹性。

首先,虽然不是立即需要的,但您应该倾向于不可变的集合而不是可变的集合,尤其是在处理并发时。这样做是一种很好的做法,这样可以防止不必要的修改,并使您可以更轻松地推断列表的状态。您的代码现在还没有损坏,可能是其他一些线程在被迭代时直接修改了listOfObjects,因此使其不可变可以防止这种情况。

换句话说,当分配给listOfObjects时,用Collections.unmodifableList(tempList)或Guava的ImmutableList.copyOf(tempList)包裹列表(不同之处在于Guava的ImmutableList实际上是列表项的副本,而unmodifableList只是使视图不可变-这意味着对基础列表的更改仍会出现)。或者只是从doSomethingToPopulateList()返回一个不可变的列表。

但是要回答您的问题,您不应该直接修改它,而是在将新列表收集到listOfObjects中后更新tempList是正确的。即使当前正在执行referToList(),这也不会造成问题。这是因为listOfObjects是参考。当你跑步

for(Object o : listOfObjects){
    doSomething(o);
}


JVM在for循环开始时获取内存引用listOfObjects所引用的内容,并迭代该内存空间中的项目。在进行迭代时,您的其他代码可以更新listOfObjects指向的内存引用(通过在updateList()中重新分配),但这不会影响for循环的运行进度。

09-27 19:54