java map同步访问_同步 - Java synchronized块与Collections.synchronizedMap

您的代码中可能存在细微的错误。

[更新:因为他正在使用map.remove(),所以这种描述并不完全有效。 我第一次错过了这个事实。 :(感谢问题的作者指出这一点。我将其余部分保留原样,但改变了主要声明,说有可能存在错误。]

在doWork()中,您可以以线程安全的方式从Map获取List值。 然而,之后,您在不安全的情况下访问该列表。 例如,一个线程可能正在使用doWork()中的列表,而另一个线程在addToMap()中调用synchronizedMap.get(key).add(value)。 这两个访问不同步。 经验法则是集合的线程安全保证不会扩展到它们存储的键或值。

你可以通过在地图中插入一个同步列表来解决这个问题

List valuesList = new ArrayList();

valuesList.add(value);

synchronizedMap.put(key, Collections.synchronizedList(valuesList)); // sync'd list

或者,您可以在doWork()中访问列表时在地图上进行同步:

public void doWork(String key) {

List values = null;

while ((values = synchronizedMap.remove(key)) != null) {

synchronized (synchronizedMap) {

//do something with values

}

}

}

最后一个选项会稍微限制并发性,但IMO会更加清晰。

另外,关于ConcurrentHashMap的快速说明。 这是一个非常有用的类,但并不总是适用于同步HashMaps的替代品。 引用其Javadocs,

在依赖于线程安全但不依赖于其同步细节的程序中,此类可与Hashtable完全互操作。

换句话说,putIfAbsent()非常适合原子插入,但不保证在该调用期间地图的其他部分不会改变; 它只保证原子性。 在您的示例程序中,您依赖于put()s以外的(同步)HashMap的同步详细信息。

最后一件事。 :)来自Java Concurrency in Practice的这句精彩报价总能帮助我设计调试多线程程序。

对于可由多个线程访问的每个可变状态变量,必须在保持相同锁的情况下执行对该变量的所有访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值