Java 通过构造函数发布对象
考虑以下类别:Java 通过构造函数发布对象,java,multithreading,synchronization,Java,Multithreading,Synchronization,考虑以下类别: class Ideone { private Map<String, String> m; public Ideone(){ synchronized(this){ m = new ConcurrentHashMap<>(); } } public synchronized Map<String, String> getM(){ retur
class Ideone
{
private Map<String, String> m;
public Ideone(){
synchronized(this){
m = new ConcurrentHashMap<>();
}
}
public synchronized Map<String, String> getM(){
return Collections.unmodifiableMap(m); //effectively immutable
}
}
我想如果我们不同步构造和getter,比如
class Ideone
{
private Map<String, String> m;
public Ideone(){
m = new ConcurrentHashMap<>();
}
public Map<String, String> getM(){
return Collections.unmodifiableMap(m); //effectively immutable
}
}
类表意符
{
私有地图m;
公共表意词(){
m=新的ConcurrentHashMap();
}
公共地图getM(){
返回集合。不可修改映射(m);//实际上是不可变的
}
}
无法保证遵守正确的状态值(例如,默认值)
但如中所述,只要允许这个
逃逸,这种同步是不可取的
问题:为什么构造函数中的同步允许
这个逃逸?您误解了答案。
让我们了解synchronized(this)
在构造函数中的作用
为了使synchronized(this)
语句有用,两个线程应该同时访问具有相同对象的同步块。
现在,其中一个线程在构造函数中,这意味着对象刚刚被创建
对于其他线程,如果要引用该对象,您应该在某个地方从构造函数泄漏当前对象(this
)
您的代码不会泄漏它,但是同步(此)
在您的代码的构造函数中没有任何值。您误解了答案。
让我们了解synchronized(this)
在构造函数中的作用
为了使synchronized(this)
语句有用,两个线程应该同时访问具有相同对象的同步块。
现在,其中一个线程在构造函数中,这意味着对象刚刚被创建
对于其他线程,如果要引用该对象,您应该在某个地方从构造函数泄漏当前对象(this
)
您的代码不会泄漏它,但是同步(this)
在您的代码的构造函数中没有任何值。答案意味着使用同步(this)
的唯一原因是this
引用已从构造函数中转义
但这种推理本身是不正确的。我为这个问题添加了另一个答案:
您已经展示了这样一种情况:乍一看,您在构造函数中使用synchronized(this)
,这是合理的,因为它确实确保了getM()
在从另一个线程调用时将为实例变量m
提供正确的值
如果没有这些同步块,情况就不一定如此-即使在构造函数完成后,另一个线程也可能看到字段m
的值null
,因为在一个线程上,构造函数中对m
的赋值与另一个线程上方法getM
中对m
的读取之间不存在before关系
但是:如何将Ideone
的实例从一个线程传递到另一个线程?如果在没有任何同步机制的字段中执行此操作,因此没有任何before关系,那么第二个线程就不能保证看到整个Ideone
实例
如果is看到实例,则实例中的数据如果正确,但在这种情况下,它也可能看到值null
但是,如果您确实使用了同步机制来传递Ideone
的实例,那么该机制已经创建了一个before-before关系,并且您不再需要在构造函数和getM
中使用synchronized
由于所有在线程之间传递对象的安全机制都涉及一个同步机制,该机制设置了“发生在发生之前”关系,因此(几乎)不需要在构造函数中使用synchronized
。答案意味着使用synchronized的唯一原因(这)
用于此
引用已从构造函数中转义的情况
但这种推理本身是不正确的。我为这个问题添加了另一个答案:
您已经展示了这样一种情况:乍一看,您在构造函数中使用synchronized(this)
,这是合理的,因为它确实确保了getM()
在从另一个线程调用时将为实例变量m
提供正确的值
如果没有这些同步块,情况就不一定如此-即使在构造函数完成后,另一个线程也可能看到字段m
的值null
,因为在一个线程上,构造函数中对m
的赋值与另一个线程上方法getM
中对m
的读取之间不存在before关系
但是:如何将Ideone
的实例从一个线程传递到另一个线程?如果在没有任何同步机制的字段中执行此操作,因此没有任何before关系,那么第二个线程就不能保证看到整个Ideone
实例
如果is看到实例,则实例中的数据如果正确,但在这种情况下,它也可能看到值null
但是,如果您确实使用了同步机制来传递Ideone
的实例,那么该机制已经创建了一个before-before关系,并且您不再需要在构造函数和getM
中使用synchronized
class Ideone
{
private Map<String, String> m;
public Ideone(){
m = new ConcurrentHashMap<>();
}
public Map<String, String> getM(){
return Collections.unmodifiableMap(m); //effectively immutable
}
}