Java volatile自定义对象-完全/深度对象可见性



我有以下内容:

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);
}
}

我的问题如下:

  1. 如果给定MyCustomObject,其ID发生更改,会发生什么?这个变化对其他线程可见吗?(没有同步(我认为是的,ID是int并更改其引用
  2. 如果给定一个MyCustomObject,它的SON id被更改,会发生什么?这种变化是否反映在其他线程中?(没有同步(我认为是的,因为之前的原因
  3. 如果在其SON字段中给定一个不带volatile关键字的MyCustomObject,则子的ID值发生更改,会发生什么情况?这一变化是否反映在其他线程中?我认为是的,因为id是int并更改其引用

THUMB规则:让我们假设以下经验规则:如果共享一个复杂对象,则在需要互斥时应该对其进行同步,但对于那些不更改引用的字段(即复杂对象而不是int或String等基元(也必须进行同步。这是必要的,因为使用同步,所有更新都被授予由java内存模型安全共享的权限。

感谢

您最初的问题是:我可以使用volatile进行地图的最新更新吗?

我希望我理解得正确。

想象一下,如果Thread B执行MyCustomObject()构造函数:这将使此MyCustomObject可用于其他线程(仅当它们遇到并读取易失性id时(。(建议设置id是构造函数中的最后一条语句(。然而,根据给定的代码示例,可能有许多这样的对象具有相同的id。

想象一下,如果thread A执行addMyCustomObject():线程A将获得最新的更新,包括正确构建的MyCustomObject实例。

想象一下,如果thread C执行getList():它可能会也可能不会返回正确的结果。这张地图是最终的,所以它有建造时正确发布的状态。然而它是一个可变的holder,这就是问题所在您需要在此处进行同步。

你能让地图也不稳定吗是的,你可以,但那会有什么结果呢。在这样的实现中,试图找出与线程相关的问题会让人发疯。

为什么不建议使用这种编码就并发环境而言,上面的代码读起来并不清楚。它很脆弱。建议使用同步结构来澄清互斥和可见性。Volatile有其用途,例如标志。

注意:Volatile用于保证可见性,锁定/同步用于可见性和原子性

如果我的解释有误,请告诉我。

编辑1:回答您更新的问题:

Q1:如果给定MyCustomObject,其ID发生更改,会发生什么?这个变化对其他线程可见吗?(没有同步(我认为是的,ID是int并更改其引用

A1:直到id被调用线程引用。

Q2:如果给定一个MyCustomObject,它的SON id被更改,会发生什么?这种变化是否反映在其他线程中?(没有同步(我认为是的,因为之前的原因

A2:同上。

Q3:如果给定一个在SON字段上没有volatile关键字的MyCustomObject,那么子的ID值会发生变化,会发生什么?这一变化是否反映在其他线程中?我认为是的,因为id是int并更改其引用

A3:只有当volatile被读取时才会再次出现。当然,一个线程可以一次又一次地调用changeSon(),而另一个线程将看不到更新的SON。

最好的方法是创建一个多线程测试工具并运行测试用例N次。我假设你有一个多核系统。尽量不要使用分配了单个核心的虚拟机。

最新更新