你说得对.get()
操作是"线程安全的",因为它保证要么返回在映射更新之前给定k
存在的PlainObject
,要么返回在该k
下添加的新对象.它永远不会返回其他对象,也不会导致程序崩溃.
BUT个
映射本身是线程安全的,这一事实绝不会保护您放置在映射in上的对象.如果您希望程序在一个线程希望与修改该对象的其他线程同时判断该对象时看到一致的值v.a
和v.b
,那么提供这种保护完全取决于您.
update:个
您的示例没有按照预期的方式使用compute
.您提供的函数永远不会返回与映射中已有的v
不同的v
.您编写的代码与此版本没有任何不同:
void act(){
PlainObject v = myMap.get("abc");
if (v != null) {
v.a = 21;
// Other work
v.b = 18;
}
}
compute
的目的是让您编写一个函数来决定是否应该用不同的对象替换贴图中的对象:
void foo() {
myMap.compute("abc", (k, v) -> {
if ((v == null) || ...other reason not to update...) {
return /*the original, UNMODIFIED*/ v;
}
else {
PlainObject new_v = new PlainObject();
new_v.a = 21;
// Other work
new_v.b = 18;
return new_v;
}
});
在这种情况下,如果某个其他线程调用myMap.get("abc")
,则可以保证要么获取原始的未修改PlainObject
,要么获取新对象.如果您的PlainObject
个实例都是effectively immutable,*,那么当get()
函数返回新对象时,它应该已经是safely published†了.
*如果在对象对其他线程可用之后,没有线程修改PlainObject
,那么它将是"有效的不可变的".
†"安全发布"意味着在新对象的初始化和任何其他线程访问它的第一次机会之间存在一种"发生在此之前"的关系.