views:

212

answers:

6

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?

+2  A: 

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

Arne Burmeister
A: 

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).

aioobe
+6  A: 

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.

Michael Borgwardt
Thanks very much.
Finbarr
A: 

It is not intended to solve ConcurrentModificationException. Any local variable used inside a method-nested-class (such as an anonymous inner class) must be declared as final. See a similar discussion from the last week here:

http://stackoverflow.com/questions/2764035/question-regarding-the-method-local-innerclasses-accesing-the-local-variables-of/2764130#2764130

Actually in case of threads there is a minor contribution here for thread safety; there will be no visibility issues on the final variable between the threads. However, this does not guarantee thread safety at all.

Eyal Schneider
+2  A: 

Consider this example:

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();

If c was not final, when you reach b.goo(), it would point to junk, since that c would be garbage-collected - A local variable after the end of a method call.

Little Bobby Tables
Do you imply that final variables do not get garbage-collected? That is false.
Pindatjuh
The problem is NOT garbage collection. The inner class has a strong reference to the variable anyway. The language designers could have allowed usage of non-final local variables inside inner classes. However, this could be confusing for the developer (see Michaels response), since it would not be clear whether assignments to the reference are seen by the inner class or not.
Eyal Schneider
@Pindatjuh - I am implying that final variables do not get garbage-colleted *when the method ends*.@Eyal - You are right, the language could have been better designed, etc. However, the current design is what we have...
Little Bobby Tables
@Little Bobby Tables: they are only GCed when the reference-count is zero, which **may** be at the end of a method. In your example `c` is only GCed when the retuned `B` is, because there is a reference possibility in `goo()`. Also `c` needs to be initialized to **something** (null or instance), because `final` variables don't have default value.
Pindatjuh
+1  A: 

declaring a method variable final means that it's value can't change; that it can only be set once. how does that apply in this context?

i have known about this restriction with anonymous classes for some time, but i never quite understood why. i see that no one else really does either from the responses so far. some googling turned up the below which i think does a good job of explaining it.

An anonymous local class can use local variables because the compiler automatically gives the class a private instance field to hold a copy of each local variable the class uses. The compiler also adds hidden parameters to each constructor to initialize these automatically created private fields. Thus, a local class does not actually access local variables, but merely its own private copies of them. The only way this can work correctly is if the local variables are declared final, so that they are guaranteed not to change. With this guarantee in place, the local class is assured that its internal copies of the variables accurately reflect the actual local variables.

credit to: http://renaud.waldura.com/doc/java/final-keyword.shtml#vars

certainly not obvious and something that i think the compiler really should be hiding from developers.

Jeff
Great answer, bit technical. I like to add **why** it needs that guarantee: because the inner-class might be GCed and if the local variable changes later on and the change needs to be reflected to the inner-class instance, which is GCed: a problem avoided if the variable is final.
Pindatjuh