【问题标题】:Synchronized objects while iterating ArrayList迭代 ArrayList 时同步对象
【发布时间】:2013-09-04 10:24:28
【问题描述】:

假设我有以下场景:

final int index = 10;
Phone phone = phoneList.get(index);
synchronized(phone)
{
   //some code runs here
}

所以当电话对象(通过 phoneList.get() 方法获得)被锁定时,另一个线程可以执行该方法:

phoneList.remove(index);

并将给定索引处的电话对象设为空?

【问题讨论】:

  • 当然可以,为什么不呢?您没有在列表本身上同步。
  • 是的,它会...如果您想避免同样的情况,请在列表中进行同步...stackoverflow.com/questions/1431681/… 可能会帮助您

标签: java synchronization thread-safety


【解决方案1】:

是的。为什么不呢?

但是,phone 仍然指向同一个对象。即该对象已从列表中删除,但 jvm 仍然具有对它的引用。

【讨论】:

    【解决方案2】:

    一个操作与另一个无关:synchronized 不保护对任何特定对象的访问。如果您的remove 操作在使用与锁相同的对象的synchronized 块内,那么它将不得不等待;如果不是,它将成功删除该对象,而不会影响将其用作锁的synchronized 块。从列表中删除对象不会将对象变成垃圾,直到它的监视器被任何线程锁定。

    【讨论】:

    • 那么我应该先同步列表然后再同步电话对象还是在删除电话对象之前我必须锁定它?
    • 这通常无法回答,但如果您只是从列表中删除一个项目而不更改项目本身的任何内容,我不明白您为什么要锁定该项目。但最重要的是,您必须一方面了解您自己的应用程序逻辑,另一方面了解 Java 锁的精确语义,然后将这两者结合成一个锁定方案,为您提供完全的线程安全。
    【解决方案3】:

    当然。锁定Phone 不会锁定列表。

    此外,要从列表中删除一个元素,您不需要使用该元素。删除很简单:

    backingArray[i] = null;
    

    【讨论】:

      【解决方案4】:

      是的。

      由于您在Phone 实例上进行同步,因此这是可能的。另一个线程可以从ArrayList 中删除相同的phone 对象。但是您的 phone 引用将指向同一个实例。

      为确保没有其他线程可以从其他地方访问您的列表,请在列表本身上同步 -

      synchronized(phoneList)
      {
          //some code runs here
      }
      

      【讨论】:

        【解决方案5】:

        这里,它只是为synchronized内部的一组语句提供synchronization,而不关心获得的phone实例。从phoneList 中删除phone 对象是可能的。但是请记住,Java 不会从内存中删除一个对象,直到它还剩下一些引用。

        【讨论】:

          【解决方案6】:

          当您执行 phoneList.get(index) 时,它会为您提供从列表到 Phone 对象的对象引用。

          由于仅同步电话对象,您可以从列表中删除元素。因此,当您尝试从列表中删除元素时,您将不会收到UnsupportedOperationException

          但如果引用丢失或为空。当您尝试对电话对象进行操作时,您可能会收到NullPointerException

          【讨论】:

            猜你喜欢
            • 2018-05-23
            • 1970-01-01
            • 2014-07-12
            • 1970-01-01
            • 1970-01-01
            • 2013-09-08
            • 2018-12-23
            • 1970-01-01
            • 2017-09-30
            相关资源
            最近更新 更多