【问题标题】:What object should I lock on when I am passing a Collection<Foo> into a separate class?当我将 Collection<Foo> 传递给单独的类时,我应该锁定什么对象?
【发布时间】:2009-07-22 03:57:04
【问题描述】:

请参考UML

Connection 类的构造函数通过

初始化它的 foos 成员
foos = Collections.synchronizedList( new ArrayList<Foo>(10) );

当 Connection#start() 被调用时,它会创建一个 Poller 实例(同时将 foos 引用传递给 Poller 的构造函数)并启动 Poller(Poller 是一个 Runnable)。

问题Poller 线程将根据外部事件在列表中添加和删除对象。客户端会定期调用 Connection#snapshot() 来检索列表。由于 Poller 中的实现会在添加过程中执行检查以避免重复,因此它不是线程安全的。

例如Poller#run的实现

if( _foos.indexOf( newFoo ) == -1 )
{
    _foos.add( newFoo );
}

我可以在 ConnectionPoller 中同步什么以保证线程安全?

【问题讨论】:

  • 您可以在问题中嵌入图片,无需使用外部链接。

标签: java multithreading concurrency thread-safety


【解决方案1】:

我将看看 CopyOnWriteArrayList 作为上面示例中的 ArrayList 的替代品。这样你就不需要同步任何东西,因为你有一个开箱即用的线程安全集合,可以这么说......

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CopyOnWriteArrayList.html

从 API CopyOnWriteArrayList 是...

ArrayList 的线程安全变体 其中所有变异操作(添加, 集,等等)由实现 制作底层证券的新副本 数组。

n.b.如果遍历次数超过对集合的添加/更新次数,这只是一个可行的解决方案。是这样吗?

【讨论】:

    【解决方案2】:

    有一个使用接口和匿名内部类的干净解决方案。

    Connection 类中添加以下内容:

    public static interface FooWorker {
        void onFoos(List<Foo> list);
    }
    
    public synchronized void withFoosSafely(FooWorker worker) {
        worker.onFoos(foos);
    }
    

    Poller 类中执行以下操作:

    public void doWork() {
        connection.withFoosSafely(new FooWorker() {
             public void onFoos(List<Foo> list) {
                  /// add, remove and change the list as you see fit
                  /// everything inside this method is thread-safe
             }
        });
    }
    

    它需要一些额外的代码(Java 中还没有闭包),但它保证了线程安全并确保客户端不需要处理锁定 - 未来潜在的错误更少。

    【讨论】:

      【解决方案3】:

      您可能会从snapshot() 返回一个新列表:

      public List<Foo> snapshot() {
          return new ArrayList<Foo>(foos);
      }
      

      鉴于您要返回“快照”,我认为该列表仅在返回时才保证是最新的。

      如果您希望客户端从 foos 添加/删除成员,那么您可能需要将这些操作公开为 Connection 上的方法。

      【讨论】:

      • 不允许客户端在快照中添加/删除。
      【解决方案4】:

      也许我没有理解重点,似乎Connection#snapshot 应该在this(或_foos)上同步,管理Connection._foosPoller 的代码块也是如此。

      我错过了什么?

      【讨论】:

      • Poller 是一个单独的类,它不是 Connection 的内部类!
      • 这并不能阻止它在 Connection 上有一个同步块。我确定它引用了它管理器的 Connection,否则它怎么管理?
      猜你喜欢
      • 2016-01-23
      • 1970-01-01
      • 1970-01-01
      • 2012-01-25
      • 1970-01-01
      • 2012-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多