2016-03-22 128 views
1

我對將實例和局部變量作爲參數傳遞給線程有疑問。多線程:將實例和局部變量傳遞給線程

讓我告訴你一個簡單的例子:

public class Foo { 
    private int num; 
    private String str; 

    public Foo(int num, String str){ 
     this.num = num; 
     this.str = str; 
    } 

    public int getNum() { 
     return num; 
    } 

    public String getStr() { 
     return str; 
    } 
} 


public class FooRunnable implements Runnable { 

    private Foo foo; 

    public FooRunnable(Foo foo){ 
     this.foo = foo; 
    } 

    @Override 
    public void run() { 
     System.out.println("Number =" +foo.num); 
     System.out.println("String =" +foo.str);  
    } 
} 

public class Test { 

private Foo fooField; 

public Test(){ 
    fooField = new Foo(4, "four"); 
} 

public void launchField(){ 
    Thread th = new Thread(new FooRunnable(fooField)); 
    th.start(); 
} 

public void launchLocalVariable(){ 
    Foo fooLocal = new Foo(5, "five"); 
    Thread th = new Thread(new FooRunnable(fooLocal)); 
    th.start(); 
} 

public static void main(String[] args) { 
    Test test = new Test(); 
    test.launchField(); 
    test.launchLocalVariable(); 
} 

}

這只是個愚蠢的程序,啓動兩個線程:一個傳遞一個實例變量作爲參數傳遞給螺紋等傳遞一個局部變量。稍後,兩個線程都將傳遞的參數中的內容寫入控制檯。

在局部變量的情況下,我確信它的行爲是線程安全的。在第二種情況下,我認爲它不會,因爲可能緩存該變量。你怎麼看待這件事?我錯了嗎?

回答

0

這很簡單:如果信息可以通過線程進行更改,則您總是需要擔心線程安全。

重要的部分是:能夠改變。

在你的例子中,Foo的字段是隻讀的。 Foo對象創建後無法更改它們。因此,任何Foo對象的使用都是線程安全的。即使你給同一個Foo對象10個不同的線程,他們將始終看到相同的數據。

這個類的屬性被稱爲不變性;並且您可以通過使用Foo中的兩個字段的final關鍵字來使其更加明確。簡單地說:如果您可以將所有課程設計爲不可改變的,那麼對於線程安全性的擔憂就會少得多。

但是,如果Foo上有setter會使其他人在創建Foo對象時更改字段;那麼「本地」對比領域確實會有所作爲。

+0

謝謝@Jägermeister,我明白了。但是,在我爲Foo類定義setter並使用它分配值的情況下,哪種情況會是線程安全的?我認爲只是「本地」樣本會完全線程安全,不是嗎? – javer

+0

我想我告訴過你需要知道什麼。重點:如果任何其他線程能夠改變對象,那麼你有一個潛在的問題。奇怪的例子:假設你的類Foo有靜態字段......那麼創建Foo對象的位置並不重要。請記住:實際上,您的物體確實需要「背景」。如果你可以創建一個「局部變量」,而沒有其他人可以訪問它,那就太好了。但是你很快就會發現,這會以其他方式限制你。因此,「生成一切」本地是一個很好的政策,但你不會總能實現它! – GhostCat