有一个服务包含一个final
字段。
@Service
public class RegularService {
private final DataMap map = new DataMap();
....
}
这个final
字段有一个类DataMap
,看起来像这个
class DataMap {
private Map<UUID, String> content1 = new HashMap<>();
private Map<UUID, String> content2 = new HashMap<>();
void updateContent(UUID id, String data) {
if (content1.containsKey(id)) {
....
return;
}
if (content2.containsKey(id)) {
content1.put(id, data);
content2.remove(id);
return;
}
content2.put(id, data);
}
问题是,updateContent
是否具有竞赛条件?问题是,理论上使用UUID
意味着不同的线程永远不会访问相同的条目。。。
如果是,那么是否需要同步整个updateContent
方法,或者仅使用ConcurrentHashMap
就足够了?
问题是,在理论上使用UUID意味着不同的线程永远不会访问相同的条目。。。
这根本不是真的。这并不能保证。你是怎么得出这个结论的?我很想知道。
如果是,那么是否需要同步整个updateContent方法,或者只使用ConcurrentHashMap就足够了?
您不必同步整个函数,只需同步修改映射的位即可。您可以使用ConcurrentHashMap来解决此问题,但这会对性能造成重大影响。
使用UUID作为密钥时映射的线程安全性
映射的线程安全性实际上与所讨论的关键对象无关。仅仅因为UUID.randomUUID()
返回一个唯一的UUID并不能以某种方式保证线程安全。问题在于内存同步,以及线程将如何查看和发布对映射的更改以及协调多个映射操作。
问题是
updateContent()
是否具有竞争条件?
是的。首先,如果不使用同步或并发的Map
实现,就无法使用多个线程更新Map
。ConcurrentHashMap
将负责对映射的修改和线程之间内存的发布,以保持它们的同步。但是,由于您正在对需要协调的映射进行多个操作,因此需要添加更多的同步。
如果是,那么是否需要同步整个
updateContent()
方法,或者只使用ConcurrentHashMap就足够了?
由于要对2个映射进行多次更改,因此需要使用synchronized
或以其他方式锁定多个操作。一旦做到了这一点,就没有必要使用ConcurrentHashMap
。您可以使方法synchronized
锁定其中一个映射,也可以使特定的final Object lockObject = new Object()
用于锁定操作。
例如,在没有锁的情况下,没有任何东西可以保护线程1查看content1
不包含id XXX,然后在线程2将其添加到content1
之前继续检查content2
。所以thread1会覆盖thread2的data
,我想这不是你想要的。