2013-07-21 48 views
2

我的問題是爲什麼我應該使用final來裝飾變量list?它被匿名內部類的實例使用沒有final,它不會被編譯。爲什麼我應該在多線程程序中「最終」共享變量

的代碼如下所示:

public class TwoThreadsOneListCurrModi 
{ 
    public static void main(String[] args) 
    {  
    final List<String> list = Collections.synchronizedList(new ArrayList<String>()); 

    for (int i =0 ; i<20;i++) 
     list.add(String.valueOf(i)); 
    Thread t1 = new Thread(new Runnable(){ 

     @Override 
     public void run() 
     { 
      synchronize(list) { 
      System.out.println("size of list:" +list.size()); 
      } 
     } 
    }); 

    t1.start(); 
    } 
} 

但是,如果使用普通的類,它是好的。

public class TwoThreadsOneListCurrModi2 

{ 
    public static void main(String[] args) 
    {  
    final List<String> list = Collections.synchronizedList(new ArrayList<String>()); 
    initialize list; 

    Thread t1 = new WorkThread(list); 
    Thread t2 = new WorkThread(list);  
    t1.start(); 
    t2.start(); 
    } 
} 
class WorkThread extends Thread{ 
    List<String> list; 
    public void run(){ 
     do sth with list and synchronize block on list 
    } 
    Work1(List<String> list) 
    { this.list = list; } 
} 
+1

的確,我們投票選出一個重複的問題來結束這個問題。 –

回答

11

這與多線程無關。它在那裏,因爲你正試圖從匿名內部類的方法訪問list。在這種情況下,Java將始終簽署一個錯誤。

對於您的情況,您在此處使用new關鍵字在此處創建Runnable的匿名實例。您試圖從run解除引用的所有內容都需要爲final

如果您對最終關鍵字的必要性感到好奇,您可以查看Jon Skeet的exhaustive answer,這將深入解釋它。

問題是,當你創建一個匿名內部類的實例時,在該類中使用的任何變量都會通過自動生成的構造函數複製它們的值,如果該變量可以被其他修改的方法,反之亦然。

+3

你可能想提一下變量需要最終的方法,關於Java在給匿名內部類之前創建變量的副本等等。 –

+0

感謝您指出了這一點。 –

+1

如果它不是最終的,這將意味着封閉式的行爲,Java不支持。 – Cephalopod