从Hashmap同时添加或删除元素并实现同步

时间:2016-11-04 04:54:26

标签: java concurrency hashmap

我是Java和并发新手。

分配的目的是学习并发性。 - 所以在回答这个问题时请记住,我应该只使用Hashmap(本质上不同步)并自己同步。如果你提供了更多的知识,但是不需要它。

我声明了这样的哈希图:

private HashMap<String, Flight> flights = new  HashMap<>();

recordID是要删除的航班的关键。

Flight flightObj = flights.get(recordID);

synchronized(flightObj){
                    Flight deletedFlight = flights.remove(recordID);
                    editResponse = "Flight with flight ID " + deletedFlight.getFlightID() +" deleted successfully";
                    return editResponse;
                }

现在我怀疑:在flightObj的基础上同步是否合适?

怀疑2:

Flight newFlight = new Flight(FlightServerImpl.createFlightID());
flights.put(newFlight.getFlightID(),newFlight); 

如果我使用上面的代码创建flightts,并且如果多于1个线程尝试执行此代码,那么会出现任何数据一致性问题吗?为什么或为什么不呢?

提前致谢。

2 个答案:

答案 0 :(得分:1)

快速回答你的问题:

两者都不合适 - 你不能并行删除两个不同的对象,也不能并行添加两个不同的对象。

来自java documentation

  

如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步。 (结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键关联的值不是结构修改。)这通常通过同步自然封装映射的某个对象来完成。 。如果不存在此类对象,则应使用Collections.synchronizedMap方法“包装”该映射。这最好在创建时完成,以防止意外地不同步访问地图:

因此,许多线程可以同时使用get甚至put来替换对象。

但是如果你删除或添加一个新对象 - 你需要在调用任何hashmap函数之前进行同步。

在这种情况下,您可以执行文档中建议的操作并使用全局锁定。但是,似乎由于仍然允许一些有限的并发,你可以使用read/write lock来获得并发性。

答案 1 :(得分:0)

您可以执行以下操作

class MySynchronizedHashMap<E> implements Collection<E>, Serializable {
    private static final long serialVersionUID = 3053995032091335093L;

    final Collection<E> c;  // Backing Collection
    final Object mutex;     // Object on which to synchronize

    SynchronizedCollection(Collection<E> c) {
        this.c = Objects.requireNonNull(c);
        mutex = this;
    }

    public boolean add(E e) {
        synchronized (mutex) {return c.add(e);}
    }
    public boolean remove(Object o) {
        synchronized (mutex) {return c.remove(o);}
    }
}

MySynchronizedHashMap mshm = new MySynchronizedHashMap<>(new HashMap<String, Flight>());
mshm.add(new Flight());