Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通过构造函数发布对象_Java_Multithreading_Synchronization - Fatal编程技术网

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