【发布时间】:2020-05-02 17:47:43
【问题描述】:
我有以下几点:
public class MainClass {
private final Map<Integer, List<MyCustomObject>> myMap = new HashMap<>();
public synchronized addMyCustomObject(MyCustomObject customObj) {
List<MyCustomObject> customObjList = myMap.get(customObj.getId());
if (customObjList == null) {
customObjList = new LinkedList<>();
}
customObjList.add(customObj);
}
public synchronized List<MyCustomObject> getList(int customObjId) {
return myMap.get(customObjId);
}
}
public class MyCustomObject {
private volatile MyCustomObject sonCustomObject;
private volatile int id;
public MyCustomObject(MyCustomObject sonCustomObject, int id) {
this.id = id;
this.sonCustomObject = sonCustomObject;
}
public void changeId(int newId) {
this.id = newId;
}
public int getId() {
return this.id;
}
public void changeSon(MyCustomObject sonCustomObject) {
this.sonCustomObject.setId(-1);
this.sonCustomObject = sonCustomObject;
this.sonCustomObject.setId(this.id);
}
}
我的问题如下:
- 如果给定一个 MyCustomObject,它的 ID 发生了变化,会发生什么?这种变化对其他线程可见吗? (不同步)我认为是的,ID 是 int 并更改了它的引用。
- 如果给定一个 MyCustomObject,它的 SON'S id 发生了变化,会发生什么?此更改是否反映到其他线程? (不同步)我认为是的,因为前面的原因
- 如果在其 SON 字段中给定 MyCustomObject without volatile 关键字,儿子的 ID 值发生更改,会发生什么情况?此更改是否反映到其他线程?我认为是的,因为 id 是 int 并且会更改其引用。
经验法则: 让我们假设以下经验法则:如果一个复杂对象是共享的,那么当需要互斥时它应该同步,但是对于那些不改变其引用的字段也必须进行同步(即复杂对象而不是像 int 或 String 这样的原语)。这是必需的,因为使用同步,所有更新都被授予由 java 内存模型安全共享。
谢谢
【问题讨论】:
-
Volatile
myList在这里基本上什么都不做,因为您没有重新分配列表,并且波动仅应用于列表引用,而不是列表的结构或内容: 你也可以把它做成final。 -
感谢您的回答,所以我实际上并没有正确刷新我的共享对象。我猜只是简单地重新分配同一个对象而不进一步实例化是不够的,对吧?
-
@AndyTurner 我已经更新了我的代码,“myMap”的引用从未改变,但它的内部内容会改变,所有线程都可以看到它吗?
-
不,
HashMap和LinkedList在没有外部同步的情况下都不安全,如其 Javadoc 中所述。 -
所以这意味着如果没有显式同步,我将永远不会在所有线程中更新值,对吧?因此,如果我知道我的参考不会及时更改,那么 volatile 关键字将毫无用处。所以让我们假设我已经有一个 MyCustomObject 实例,并且我想在它已经添加到地图后更改它的 ID(使 add 方法同步)。在我将此更改放入同步块之前,我的更改不会得到反映,对吗?我的 ID 是不稳定的,它改变了它的引用,所以在这种情况下可能不需要同步,对吧?
标签: java concurrency volatile