【问题标题】:Updating an active collections on a scheduler更新调度程序上的活动集合
【发布时间】:2016-11-18 00:35:26
【问题描述】:

我认为这可能是一件容易的事,但想知道是否有这种模式或优雅的方式。我看了看番石榴。 我有一个类级别的列表,一个在调度程序上引用这个 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 的副本,但不确定它的效率如何

【问题讨论】:

    标签: java spring collections guava


    【解决方案1】:

    tl;dr - 您的代码是安全的,但可以更好地应对未来的错误。

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

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

    但要回答您的问题,您可以不直接修改它,而是在您将新列表收集到tempList 后更新listOfObjects。即使referToList() 当前正在执行,这也不会导致问题。那是因为listOfObjects 是一个参考。当你运行时

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

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

    【讨论】:

    • 好点,但代码安全。该列表不是从updateList 方法安全发布的;执行referToList 的线程可能会看到列表处于不一致状态。除非我遗漏了一些东西并且保证同一个线程执行这两种方法。
    • 给变量赋值是一个原子操作,对吧?这里会看到什么不一致的状态?
    • 是的,Java 中的变量赋值始终是原子的。但是可见性是一个单独的问题——如果没有安全发布,线程 A 可能永远会看到线程 B 的分配。或者更糟糕的是,它可能会看到引用的分配但看到引用的对象处于半建成状态。请参阅this SO questionthis article by Brian Goetz(主要是关于安全构造,但标题为“可见性危害”的部分也适用于此)。
    猜你喜欢
    • 2016-08-28
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多