【问题标题】:Do you have to synchronize concurrent collections?您必须同步并发集合吗?
【发布时间】:2015-04-22 09:36:27
【问题描述】:

想象一下下面的例子: 一个应用程序启动两个线程。 Provider 类持有并发集合并向其写入数据。消费者从集合中读取数据。

下面的代码是正确的还是我必须添加同步?

public class Application{
    public static void main(String...args) throws Exception{
        Provider p = new Provider();
        new Thread(p).start();
        new Thread(new Consumer(p)).start();

        // Make sure the example stops after 60 seconds
        Thread.sleep(1000*60);
        System.exit(0);
    }
}

/**The Provider (writes data to concurrent collection)*/
class Provider implements Runnable{

    private ConcurrentMap<Integer, String> map 
        = new ConcurrentHashMap<Integer, String>(20, 0.5f, 1);

    public void run(){
         Integer i = 1;
         while(true){
             try {
                 Thread.sleep(500);
             } catch (InterruptedException ignore) {
             }
             // Synchronization ?
             map.put(i, i.toString());
             i++;
         }
    }

    public ConcurrentMap<Integer, String> getMap(){
         // Synchronization ?
         return map;
    }

}

/**The Consumer (reads data from concurrent collection)*/
class Consumer implements Runnable{

    private Provider provider;

    public Consumer(Provider p){
        provider = p;
    }

    public void run(){
        while(true){
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException ignore) {
             }
            // Synchronization ?
            ConcurrentMap<Integer, String> m = provider.getMap();
            if(m!=null)
                for(String s: m.values())
                    System.out.print(s); 
            System.out.println();               
        }
    }

}

【问题讨论】:

    标签: java collections concurrency


    【解决方案1】:

    来自ConcurrentHashMap documentation

    对于聚合操作 如putAllclear,并发检索可能 仅反映某些条目的插入或删除。相似地, 迭代器、拆分器和枚举返回反映 哈希表在创建时或之后的某个时间点的状态 迭代器/枚举。他们确实抛出ConcurrentModificationException。 但是,迭代器被设计为一次只能由一个线程使用。 请记住,聚合状态方法的结果包括 sizeisEmptycontainsValue 通常是 仅当地图未在其他线程中进行并发更新时才有用。 否则,这些方法的结果反映了瞬态 可能足以用于监控或估计目的,但不 用于程序控制。

    所以您不需要进行同步,因为您不会得到ConcurrentModificationException。您是否想要取决于您的程序逻辑。

    【讨论】:

      【解决方案2】:

      并发集合的突变是线程安全的,但是不能保证数据的一致性。

      备用Collections.synchronized[...] 习惯用法与显式同步相结合,将保证线程安全数据一致性(以性能为代价)。

      【讨论】:

      • 你能给我一个并发收集的数据一致性错误的例子吗?
      • @SteveS。不是这样的错误,因为正如T.J.Crowder 所说,你不会得到ConcurrentModificationException。但是,例如,操作顺序可能与预期不同。 documentation"However, even though all operations are thread-safe, retrieval operations do not entail locking, and there is not any support for locking the entire table in a way that prevents all access."中的一个很好的流行语
      猜你喜欢
      • 1970-01-01
      • 2013-02-15
      • 2011-07-16
      • 2017-10-08
      • 2020-01-29
      • 2013-11-14
      • 2020-11-12
      • 2023-01-20
      • 1970-01-01
      相关资源
      最近更新 更多