对于具有同步方法的路由器表,我有以下类:
public class RouterTable {
private String tableForRouter;
private Map<String,RouterTableEntry> table;
public RouterTable(String router){
tableForRouter = router;
table = new HashMap<String,RouterTableEntry>();
}
public String owner(){
return tableForRouter;
}
public synchronized void add(String network, String ipAddress, int distance){
table.put(network, new RouterTableEntry(ipAddress, distance));
}
public synchronized boolean exists(String network){
return table.containsKey(network);
}
}
多个线程将读取和写入HashMap。我想知道是否最好删除方法上的synchronized并且只使用Collections.synchronizedMap(new HashMap&lt; String,RouterTableEntry())`Java中最明智的方法是什么?
答案 0 :(得分:4)
我建议使用ConcurrentHashmap。这是Java的更高版本中引入的更新的数据结构。它提供了线程安全性并允许并发操作,而不是同步映射,它将一次执行一个操作。
如果地图是唯一需要线程安全的地方,那么只需使用ConcurrentHashmap即可。但是,如果你有涉及更多状态变量的原子操作,我建议使用同步代码块而不是同步函数
答案 1 :(得分:1)
如果没有对先发生过的关系和时间点正确性的严格要求,那么在现代java中要做的明智的事情通常就是使用ConcurrentMap。
否则,是的,使用Collections#synchronizedMap
既更安全又更有效(因为您不会包含任何不需要同步的第三代码),而不是自己手动同步所有内容。
答案 2 :(得分:1)
最好的方法是使用java.util.concurrent.ConcurrentHashMap,它是从头开始设计的,用于并发访问(读和写)。
像您一样使用同步,但显示高争用,因此不是最佳性能。通过Collections.synchronizedMap()获得的集合将执行相同的操作(它仅使用同步方法包装标准集合)。
相反,ConcurrentHashMap使用各种技术来保证线程安全并提供良好的并发性;例如,它有(默认情况下)16个区域,每个区域由一个不同的锁保护,因此最多16个线程可以同时使用它。答案 3 :(得分:1)
同步地图将阻止您的班级用户进行有意义的同步。
一旦他们进入if语句,他们将无法知道存在的结果是否仍然有效,并且需要进行外部同步。
使用您显示的同步方法,他们可以锁定您的类,直到他们完成一组方法调用。
另一种选择是不进行同步,让用户处理它,为了安全起见,他们需要这样做。
添加自己的同步是HashTable的错误。
答案 4 :(得分:1)
当前的常见样式倾向于优先使用同步集合而不是访问它们的方法的显式同步资格。但是,这不是一成不变的,您的决定应取决于您使用此代码的方式/将来会使用此代码。
要考虑的要点:
(a)如果您的地图将由RouterTable
之外的代码使用,那么您需要使用SynchronizedMap
。
(b)OTOH,如果你要向RouterTable
添加一些额外的字段,它们的值需要与地图中的值一致(换句话说:你想要改变地图和在一个原子量子中发生的附加字段),那么你需要使用synchrnoized
方法。