2015-04-03 68 views
0

有多個線程訪問單個對象。爲了避免內存一致性錯誤,我使用了該對象的同步方法。
這是否意味着當我在該對象上同步時,只有對象的字段被同步(而不是對象的字段的字段)? 例如:同步對象,然後在該對象的字段上

public class Class1 { 

    private Object value1; 

    public Object getValue1() { 
     return this.value1; 
    } 

    public void setValue1(Object value1) { 
     this.value1 = value1; 
    } 

} 

哪個代碼是正確的(Class2Class3),爲什麼?

public class Class2 { 

    private final Class1 object1 = new Class1(); 

    private Object value2; 

    public synchronized void setValues(Object value1, Object value2) { 
     object1.setValue1(value1); 
     this.value2 = value2; 
    } 

    public synchronized Object[] getValues() { 
     return new Object[] { object1.getValue1(), this.value2}; 
    } 

} 

public class Class3 { 

    private final Class1 object1 = new Class1(); 

    private Object value2; 

    public synchronized void setValues(Object value1, Object value2) { 
     synchronized (object1) { 
      object1.setValue1(value1); 
     } 
     this.value2 = value2; 
    } 

    public synchronized Object[] getValues() { 
     Object value1; 
     synchronized (object1) { 
      value1 = object1.getValue1(); 
     } 
     return new Object[] { value1, this.value2}; 
    } 

} 

更具體的:

Class2 obj = new Class2(); 

// thread 1 
obj.setValues(..., ...); 

// thread 2 
Object[] values = obj.getValues(); 

由於兩個setValuesgetValues同步會有在Class2this.value2 = value2;return new Object[] {..., this.value2};之間之前發生的關係。
但是object1呢?沒有保證this.value1 = value1;發生在return this.value1;Class1之前。不是嗎?

回答

0

他們可能都是對的,而是因爲你是如何使用他們(沒有可以使用object1value2其他比你所創建的實例的方法的細節而已,因爲object1value2和私有的情況下, )。您的主要問題的答案:

這是否意味着當我在該對象上同步時,只有對象的字段被同步(而不是對象的字段的字段)?

..是,只能訪問該對象的字段,而不是字段的字段,是同步的。

下面是實際上可以證明一個問題的例子:

class Foo { 
    Class1 c1; 

    Foo(Class1 c) { 
     this.c1 = c; 
    } 

    synchronized Object getValue1() { 
     return c1.getValue1(); 
    } 

    synchronized void setValue1(Object newValue) { 
     c1.setValue1(newValue); 
    } 
} 

就這樣,這是可能的Foo兩個實例共享Class1相同例如:

Class1 c1 = new Class1(); 
Foo f1 = new Foo(c1); 
Foo f2 = new Foo(c2); 

...並且由於同步僅同步對Foo實例的訪問,因此您可以對實例進行非同步訪問他們都在使用。

+0

因此,在Class2中訪問'object1'的'value1'時不會出現內存一致性錯誤?爲什麼? 'object1'和'value2'都是參考字段,只有那些字段的值(即對象在存儲器中的地址)被同步。 'value2'很好,因爲我們不訪問它自己的狀態。但是'object1'的'value1'呢?是否有可能獲得「舊」價值而不是新價值?爲什麼? – Victor 2015-04-03 08:41:18

+0

@Victor:你不同步字段;你同步*線程*。再次說明:您的示例具有一個** private **'Class'實例,並且該實例的唯一訪問權限是通過同步包含它的實例的同步方法。因此,在任何給定的時間只有一個線程可以使用這些方法,並且不必進行進一步的同步。但那只是因爲你的類有一個沒有其他人訪問的私有實例。不要想到同步字段,請考慮使用這些字段的*線程*。 – 2015-04-03 09:00:10