Collections.synchronizedMap()和HashMap周围的包装器之间有什么区别,所有方法都是同步的。我没有看到任何差异,因为Collections.synchronizedMap()在内部为所有方法保持相同的锁。
基本上,以下代码片段有什么区别
Class C {
Object o;
public void foo() {
synchronized(o) {
// thread safe code here
}
}
}
和
Class C {
Object o;
public synchronized void foo() {
}
}
答案 0 :(得分:3)
只有一个区别:
Collections.synchronizedMap 能够使用与自身不同的监视器。
使用synchronized方法与使用sychnchonized(this)
- block相同,这意味着包装器将成为监视器,并且可以从包装器的外部锁定。
如果您不希望外部应用程序锁定您的显示器,则需要隐藏它。
另一方面,如果你想以线程安全的方式调用多个方法,那么它是锁定整个集合的最简单方法(但它确实不是很可扩展的。)
Ps:为了重用,最好将方法调用委托给backup-Map而不是覆盖类,因为您可以在以后切换到另一个Map实现,而无需更改包装器。
答案 1 :(得分:2)
两种方法都在对象上获取监视器,因此应该执行完全相同的操作。造成这种差异的主要原因是建筑。同步包装器允许轻松扩展基本的非线程安全变体。
如果说不使用它们,请使用ConcurrentHashMap。它使用锁定条带,因此使用它比任何一种方法都快得多(因为它们在开销+争用方面是相同的)。锁定条带允许背衬阵列的各个部分独立锁定。这意味着两个线程请求获取相同锁的可能性较小。
答案 2 :(得分:1)
不要重新发明轮子并使用API提供的内容。
答案 3 :(得分:0)
你应该总是装饰而不是把所有东西和所有的东西都集中在一个大的特色课上。
始终使用普通Map并使用Collections进行装饰,或使用java.util.concurrent并使用真正的锁,这样就可以原子地检查和更新地图。明天您可能希望将Hashtable更改为Treemap,如果您遇到哈希表,则会遇到麻烦。
答案 4 :(得分:0)
那么,你为什么这么问? :)你真的相信如果将类放在java.util包中那么一些魔法会发生并且它的java代码会以某种棘手的方式工作吗?
它实际上只使用synchronized {}块包装所有方法,仅此而已。
UPD:不同之处在于,如果您使用同步集合而不是自己执行所有同步操作,那么您犯错的机会就会少得多。
UPD 2:正如你在资源中看到的那样,他们使用'互斥'对象作为监视器。在方法签名中使用synchronized修饰符(即synchronized void doSmth()
)时,对象的当前实例(即this
)将用作监视器。下面两段代码是相同的:
1
synchronized public void doSmth () {
someLogic ();
moreLogic ();
}
synchronized public static void doSmthStatic () {
someStaticLogic ();
moreStaticLogic ();
}
2
public void doSmth () {
synchronized (this) {
someLogic ();
moreLogic ();
}
}
public static void doSmthStatic () {
synchronized (ClassName.class) {
someStaticLogic ();
moreStaticLogic ();
}
}
答案 5 :(得分:0)
如果是线程安全,请使用并发包数据结构。使用包装器类将减少对Map的所有访问,使其成为顺序队列。
a)等待在Map中完全不同点进行操作的线程将等待同一个锁。根据线程数量,这会影响应用程序性能。
b)考虑地图上的复合操作。使用带有单锁的包装器无济于事。例如。 “看看是否存在然后添加”类型的操作。线程同步将再次成为一个问题。