2013-07-21 51 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