我是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个线程尝试执行此代码,那么会出现任何数据一致性问题吗?为什么或为什么不呢?
提前致谢。
答案 0 :(得分:1)
快速回答你的问题:
两者都不合适 - 你不能并行删除两个不同的对象,也不能并行添加两个不同的对象。
如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步。 (结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键关联的值不是结构修改。)这通常通过同步自然封装映射的某个对象来完成。 。如果不存在此类对象,则应使用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());