Java synchronized()关键字 - 保护字段中引用的对象的更改?

时间:2013-11-19 16:11:20

标签: java multithreading concurrency

我知道

synchronized(objA) {
    objA.readSomething();
}

保护对象不被另一个线程修改。但是,如果将objA声明为

,该怎么办?
class A {
    public B objB; 
    public void readSoemthing() {
       objB.readSomething();
    }
}

在下一个区块中,另一个thead调用objB.modifySomething()?假设该线程以某种方式具有自己对objB的引用。

这样安全吗?如果没有,处理它的正确方法是什么(即我不希望任何线程修改A内的任何内容,即使它是指向不同对象的字段,我也不希望该对象被修改)。

synchronized(objA) {
    objA.readSomething();  // at this point antoher thread calls objB.modifySomething()
}

4 个答案:

答案 0 :(得分:4)

您问题的第一部分不正确。 synchronized块只确保在执行synchronized块时,没有其他线程可以进入也在objA引用的对象上同步的代码块。

因此,除非修改objA的所有方法都已同步,否则任何其他线程可能会同时修改objA

既然你知道这一点,你也知道任何其他线程都可以从objA获取objB并使用objB做任何想做的事情,除非objB的所有方法也在objA上同步。 / p>

这就是封装在线程安全类中至关重要的原因。访问(读取或写入)对象的共享状态的所有方法都应该通过该对象的同步方法。共享国家不应该暴露在外面。

答案 1 :(得分:2)

这不是线程安全的。这就是为什么你应该通过禁止直接访问它而将objB“封装”在objA中(即将其设为私有)。

答案 2 :(得分:1)

  

我知道

synchronized(objA) {
    objA.readSomething();
}
     

保护对象不被另一个线程修改。但是,如果objA   声明为

这不会阻止objA被另一个线程修改,它确保另一个线程在您发布的代码段中调用objA时无法获取objA.readSomething()的监视器。

答案 3 :(得分:0)

您实际上并未使用synchronized进行修改。您所做的就是阻止两个线程同时访问同一个方法(或使用相同对象实例进行同步的任何其他方法或代码块)。同步是关于并发(即多线程)而不是写保护。

如果您绝对不想修改,则应使用修饰符privateprotected,以便只能从您想要的类访问相应的write方法。

另一方面,如果你想避免并发修改,或者在写作时避免阅读(反之亦然),你需要将readwrite方法与同一个对象同步(在你的案例ObjA)。使用正确的修饰符来保护方法不被您不想要的类访问也可能是有意义的。

另请记住,如果Thread已获得对对象同步监视器的访问权限,则可以调用同一对象上同步的所有方法。