您是否必须同步并发集合?

时间:2015-04-22 09:36:28

标签: java collections concurrency

想象一下以下示例: 应用程序启动两个线程。 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();               
        }
    }

}

2 个答案:

答案 0 :(得分:2)

来自ConcurrentHashMap documentation

  

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

因此,您 需要进行同步,因为您不会获得ConcurrentModificationException。您想要是否符合您的程序逻辑。

答案 1 :(得分:2)

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

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