为什么传递给runnable的变量需要是最终的?

时间:2012-07-11 02:33:50

标签: java variables final runnable

如果我有一个变量int x = 1,比如说,我在主线程中声明了一个runnable,并且我想将x传递给runnable的run()方法,则必须将其声明为{{1} }。为什么呢?

final

3 个答案:

答案 0 :(得分:10)

因为这就是语言规范所说的。 According to Guy Steele,这个选择背后的基本原理是程序员会期望方法中的声明int x = 0导致堆栈分配的存储,但是如果你可以从方法中返回new myRun()(或者否则让myRun持续超过函数的返回值,然后你可以修改它,然后x必须被堆分配而不是你想要的语义。

他们本可以做到这一点,事实上其他语言就是这样做的。但Java设计者决定要求将x标记为final,以避免要求实现堆分配看起来像堆栈分配的存储。

(我应该注意:这不是Runnable特有的。它适用于任何匿名内部类。)

答案 1 :(得分:10)

因为如果它们能够被改变,它可能会导致很多问题,请考虑一下:

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]);
 }

这是一个粗略的例子,但你可以看到可能发生很多无法解释的错误。这就是变量必须是最终的原因。以下是对上述问题的简单修复:

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]);
 } 

如果您想要更完整的解释,它有点像同步。 Java希望阻止您从多个线程引用一个Object。这里有一些关于同步的内容:

希望这有帮助!

答案 2 :(得分:2)

多线程的大问题,以及使用它的全部原因,是同时发生了多件事。突然之间,线程访问的任何不是线程本地的变量的值都可以在任何时候改变。因此,您可能只需使用以下代码打印数字1-10:

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++ );
        }
    }
}

但实际上,如果该类中的其他代码更改了x的值,则最终可能会打印230498 - 230508. x 的值可能会在循环中间事件发生变化。如果您不能依赖具有特定值的x或保留您之前分配给它的值,那么在您的代码中使用它将变得徒劳无功。如果变量的内容可能会随着帽子的变化而变化,为什么还要使用变量?

而不是仅仅禁止你使用它,Java要求你创建它final。您可以“承诺”永远不会从另一个线程更改x的值,但为什么不首先使它final并让编译器帮助您?当然,你只能访问分配给x的初始值,但只是能够访问变量的初始值比完全不能使用它更好,这将有效地切断线程利用它的能力。来自其他同学的数据。