7

Classic example of a simple server:

class ThreadPerTaskSocketServer {
   public static void main(String[] args) throws IOException {
      ServerSocket socket = new ServerSocket(80);
      while (true) {
          final Socket connection = socket.accept();
          Runnable task = new Runnable() {
              public void run() {
                 handleRequest(connection);
              }
          };
          new Thread(task).start();
      }
   }
}

Why should the Socket be declared as final? Is it because the new Thread that handles the request could refer back to the socket variable in the method and cause some sort of ConcurrentModificationException?

4

6 回答 6

13

In this case, the variable must be final to be used inside the anonymous Runnable implmentation.

This is because that object will exist when the variable has already gone out of scope and has thus disappeared. The object gets a copy of the variable. In order to hide this, the variable must be final so that nobody can expect changes in one copy to be visible to the other.

于 2010-05-09T19:44:42.697 回答
3

考虑这个例子:

class A {
  B foo() {
    final C c;
    return new B() {
      void goo() {
        // do something with c
      }
    }
  }
}
// somewhere else in the code
A a = new A();
B b = a.foo();
b.goo();

如果 c不是最终的,当您到达时b.goo(),它将指向垃圾,因为 c 将被垃圾收集 - 方法调用结束后的局部变量。

于 2010-05-09T19:54:10.080 回答
2

声明一个方法变量 final 意味着它的值不能改变;它只能设置一次。这在这种情况下如何应用?

我已经知道匿名类的这种限制有一段时间了,但我一直不太明白为什么。我看到到目前为止没有其他人真正做到这一点。一些谷歌搜索出现在下面,我认为这很好地解释了它。

匿名本地类可以使用局部变量,因为编译器会自动为该类提供一个私有实例字段来保存该类使用的每个局部变量的副本。编译器还会为每个构造函数添加隐藏参数来初始化这些自动创建的私有字段。因此,本地类实际上并不访问局部变量,而只是访问它们自己的私有副本。唯一可以正常工作的方法是,如果局部变量被声明为 final,这样就可以保证它们不会改变。有了这个保证,本地类就可以确保其变量的内部副本准确地反映了实际的局部变量。

归功于: http ://renaud.waldura.com/doc/java/final-keyword.shtml#vars

当然不是很明显,而且我认为编译器确实应该对开发人员隐藏一些东西。

于 2010-05-09T20:46:21.260 回答
2

You need to declare it final, not only should. Without that, the compiler cannot use it in the anonymous Runnable class implementation.

于 2010-05-09T19:43:20.040 回答
0

Local variables are not shared between threads. (A local variable is a part of the activation record, and each thread has its own activation record).

Since connection is a local variable, it's not possible to share it between threads. Since its not shared between threads, you need to make it final, so it doesn't matter that it's a local variable (it can be seen more like a constant value).

于 2010-05-09T19:43:26.573 回答
0

它不是为了解决 ConcurrentModificationException。在方法嵌套类(例如匿名内部类)中使用的任何局部变量都必须声明为 final。在此处查看上周的类似讨论:

方法局部内部类访问方法的局部变量

实际上,在线程的情况下,这里对线程安全的贡献很小;线程之间的最终变量不会出现可见性问题。但是,这根本不能保证线程安全。

于 2010-05-09T19:47:46.980 回答