2013-06-11 71 views
0

我正在閱讀「實踐中的java併發」一書,並在幾頁之後出現一些疑問。與易失性,不可變對象有關的疑問以及它們用於實現同步的疑問

1)具有非前導數據類型的靈活性: 私有易變性Student s; 非易失性數據類型時,volatile的意義何在? (我認爲在這種情況下,只是認爲所有線程都可以看到Strudent對象正在指向哪個線程,而且有可能一個線程A修改了學生的一些內部成員,而這對其他線程是不可見的。 ??)

2) 即使內部成員沒有被聲明爲final,變量是不可變的嗎? 例如:

Class A { 

    private Set<String> s = new Set(); 
    public A() { 
     s.add("Moe"); 
     s.add("Larry"); 
     s.add("Curly"); 
    } 
} 

在課堂上做我們需要設置的最後使它不變或此類仍然是不變的? (因爲即使在這種情況下,我們也不能在創建對象後改變對象的狀態)。

3)書中有一個例子展示瞭如何組合使用volatile和immutable類來獲得同步。在我提出這個問題之前,我還有一個疑問。 假設有這樣一些功能:

private Student s = new Student; 

void func() { 
    s.func2();  // 1 
    if(s.isPossible()) { //2 
     s = new Student(); //3  
    } 
} 

一個)FUNC2()接取S的內部構件。現在考慮線程A在執行第1行後進入func2,並且線程B在同一時間重新分配新對象。當線程A恢復 它將使用新對象還是舊對象? (假設最初指向內存位置100(舊對象),並且在分配新對象後它開始指向200(新對象) ,則當線程A重新開始時它將訪問地址100或地址200)。 b)如果我使s變得不穩定,它會對上述情況產生什麼影響。

4)這裏是最後一個

@Immutable 
class OneValueCache { 
    private final BigInteger lastNumber; 
    private final BigInteger[] lastFactors; 
    public OneValueCache(BigInteger i, 
    BigInteger[] factors) { 
     lastNumber = i; 
     lastFactors = Arrays.copyOf(factors, factors.length); 
    } 
    public BigInteger[] getFactors(BigInteger i) { 
     if (lastNumber == null || !lastNumber.equals(i)) 
      return null; 
     else 
      return Arrays.copyOf(lastFactors, lastFactors.length); 
    } 
} 

@ThreadSafe 
public class VolatileCachedFactorizer implements Servlet { 
    private volatile OneValueCache cache = new OneValueCache(null, null); 
    public void service(ServletRequest req, ServletResponse resp) { 
     BigInteger i = extractFromRequest(req); 
     BigInteger[] factors = cache.getFactors(i); // Position A 

     if (factors == null) { 
      factors = factor(i); 
      cache = new OneValueCache(i, factors); // Position B 
     } 
     encodeIntoResponse(resp, factors); 
    } 
} 

Accroding到書類 「VolatileCachedFactorizer」 是線程安全的。這是我的推理,爲什麼它是線程安全的(糾正我,如果我錯了。)位置A和位置B是 可疑位置。位置A:由於緩存指向不可變對象,所以任何函數調用都是安全的(對吧?)。

位置B:它可以有兩個問題

一)線程看到緩存不當初始化。在這種情況下不可能作爲不可變對象保證正確初始化(對吧?)。

b)新分配的對象對其他線程不可見。這種情況不可能,因爲緩存是不穩定的(對吧?)。

但它有可能線程調用getFactors()和其他線程B重新分配緩存,在這種情況下,A將繼續看到舊對象

+0

爲什麼不問你3個單獨的問題...... 3個不同的問題? – Raedwald

+0

因爲有4個? ;) – selig

+0

這些都與我有關,如果有人問到這些問題和適當的答案,這對他/她會很有幫助。 – user1875798

回答

0

經過一些測試後發現我的所有答案。

  1. volatile只適用於參考。任何由volatile對象指向的對象都不需要在其他線程中可見。

  2. 是的最後很重要。沒有它,類的對象將不會是不可改變的。

  3. 假設一個變量「obj」在obj函數調用開始時指向位置x(放置實際對象的位置),則在函數調用期間,即使其他某個線程從位置x讀取所有成員變量在「obj」上分配一個不同的對象。

  4. 對所有答案的假設解釋是正確的。

2
  1. 是(是嗎?); volatile僅適用於其應用的參考。

  2. 否;碰巧被final字段指向的對象不會神奇地變成不可變的。
    具有可變非公有成員的對象只有不可變,如果這些成員永遠不會發生變異。 (顯然)