Why do variables passed to runnable need to be final?

13,584

Solution 1

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!

Solution 2

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

Solution 3

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.

Share:
13,584
Admin
Author by

Admin

Updated on June 03, 2022

Comments

  • Admin
    Admin about 2 years

    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 declared final. Why?

    final int x = 0;//<----must be final...
    private class myRun implements Runnable {
    
        @Override
        public void run() {
            x++;//
        }
    
    }
    
  • Admin
    Admin almost 12 years
    This would't cause a lot of problems -- many languages have full closures :-) The fact that Runnable (and presumably threads) is in the topic here is orthogonal to allowing local variables to be modified from anonymous inner types. Even if talking about something not dealing with threading, it would be the same language rules. Also, the same threading issue would result from member variables ..
  • mskw
    mskw almost 10 years
    In your "Here is a simple fix for the problem above:", won't w++ give you compilation error?! You cannot reassign w after initializing it.
  • John
    John almost 10 years
    @mskw I cannot believe nobody has said anything until now, thanks for finding that.