If I have a variable int x = 1
, say, and I declare a runnable in the main thread, and I want to pass x to the runnable\'s run()
method, it must be
Because that's what the language specification says. According to Guy Steele, the rationale behind this choice is that programmers would expect the declaration int x = 0
in a method to result in stack-allocated storage, but if you can return a new myRun()
from the method (or otherwise let a myRun
persist past the function's return) and you can modify it afterwards, then x
has to be heap-allocated instead to have the semantics you'd expect.
They could have done that, and in fact other languages have done it that way. But the Java designers decided instead to require that you mark x
as final
to avoid requiring implementations to heap-allocate what looks like stack-allocated storage.
(I should note: this isn't specific to Runnable
. It applies to any anonymous inner class.)
The big 'issue' with multithreading, and also the entire reason for using it, is that multiple things are happening at the same time. All of a sudden, the value of any variable that your thread accesses that isn't local to the thread can change at any point. Thus, you may thing you're just printing the numbers 1-10 with this code:
int x = 0; //supposing that this was allowed to be non-final...
private class myRun implements Runnable{
@Override
public void run() {
for (int i=0; i<10; i++ ) {
System.Out.Println( x++ );
}
}
}
But in reality, if other code in that class changes the value of x, you could end up printing 230498 - 230508. The value of x could event change in the middle of your loop. If you can't rely on x
having a certain value or keeping a value you assigned to it previously, it becomes futile to use it in your code. Why would you use a variable if its contents could change at the drop of a hat?
Rather than just forbidding you to use it at all, Java requires that you make it final
. You could just 'promise' to never change the value of x
from another thread, but then why not make it final
in the first place and let the compiler help you out? Granted, you can only access the initial value assigned to x
, but just being able to access the variable's initial value is better than not being able to use it at all, which would effectively cut off the thread's ability to utilize the data from the rest of your class.
Because if they are able to be changed, it could cause a lot of problems, consider this:
public void count()
{
int x;
new Thread(new Runnable()
{
public void run()
{
while(x < 100)
{
x++;
try
{
Thread.sleep(1000);
}catch(Exception e){}
}
}
}).start();
// do some more code...
for(x = 0;x < 5;x++)
for(int y = 0;y < 10;y++)
System.out.println(myArrayElement[x][y]);
}
This is a rough example but you can see where a lot of unexplained errors could occur. This is why the variables must be final. Here is a simple fix for the problem above:
public void count()
{
int x;
final int w = x;
new Thread(new Runnable()
{
public void run()
{
int z = w;
while(z < 100)
{
z++;
try
{
Thread.sleep(1000);
}catch(Exception e){}
}
}
}).start();
// do some more code...
for(x = 0;x < 5;x++)
for(int y = 0;y < 10;y++)
System.out.println(myArrayElement[x][y]);
}
If you want a more full explanation, it is sort of like synchronized. Java wants to prevent you from referencing one Object from multiple Threads. Here is a little bit about synchronization:
Hope this helped!