Reputation: 32186
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
?
Upvotes: 7
Views: 4968
Reputation: 145
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.
Upvotes: 2
Reputation: 5351
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.
Upvotes: 3
Reputation: 22446
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:
method local innerclasses accessing the local variables of the method
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.
Upvotes: 0
Reputation: 346457
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.
Upvotes: 13
Reputation: 421160
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).
Upvotes: 0
Reputation: 20614
You need to declare it final, not only should. Without that, the compiler cannot use it in the anonymous Runnable class implementation.
Upvotes: 2