关于java:为什么我应该在多线程程序中“最终”共享变量

why I should “final” sharing variable in multi-threading program

本问题已经有最佳答案,请猛点这里访问。

我的问题是为什么我应该使用final来修饰变量list?它被匿名内部类的实例使用,没有final,它不会编译。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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();  
  }
}

但是如果我用普通的课,就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;  }
}


这与多线程无关。它之所以存在是因为您试图从匿名内部类的方法访问list。在这种情况下,Java总是会签署一个错误。

在您的例子中,您正在使用new关键字在这里创建Runnable的匿名实例。你试图从run中取消引用的所有内容都必须是final

如果你对最后一个关键词的必要性感到好奇,你可以查看乔恩·斯基特的详尽答案,这对它有着深刻的解释。

要点是,当您创建一个匿名内部类的实例时,该类中使用的任何变量都通过自动生成的构造函数复制了它们的值,如果该变量可以由方法的其余部分修改,则看起来很奇怪,反之亦然。