java 为什么传递给 runnable 的变量需要是 final 的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11424753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:03:46  来源:igfitidea点击:

Why do variables passed to runnable need to be final?

javavariablesfinalrunnable

提问by

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?

例如,如果我有一个变量int x = 1,并且我在主线程中声明了一个可运行的变量,并且我想将 x 传递给可运行的run()方法,则必须声明它final。为什么?

final int x = 0;//<----must be final...
private class myRun implements Runnable {

    @Override
    public void run() {
        x++;//
    }

}

采纳答案by John

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:

如果你想要一个更完整的解释,它有点像同步。Java 想阻止您从多个线程中引用一个对象。这里有一点关于同步:

Hope this helped!

希望这有帮助!

回答by jacobm

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 = 0in a method to result in stack-allocated storage, but if you can return a new myRun()from the method (or otherwise let a myRunpersist past the function's return) and you can modify it afterwards, then xhas to be heap-allocated instead to have the semantics you'd expect.

因为这就是语言规范所说的。根据 Guy Steele 的说法,这种选择背后的基本原理是程序员希望int x = 0方法中的声明会导致堆栈分配存储,但是如果您可以new myRun()从方法中返回 a (或者让 amyRun持续超过函数的返回)并且您之后可以修改它,然后x必须进行堆分配,而不是具有您期望的语义。

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 xas finalto avoid requiring implementations to heap-allocate what looks like stack-allocated storage.

他们本可以这样做,事实上其他语言也这样做了。但是 Java 设计者决定改为要求您标记x为,final以避免要求实现对看起来像堆栈分配的存储进行堆分配。

(I should note: this isn't specific to Runnable. It applies to any anonymous inner class.)

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

回答by Gordon Gustafson

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:

多线程的一个大“问题”,也是使用它的全部原因,是多个事情同时发生。突然之间,您的线程访问的任何非线程本地变量的值都可能随时更改。因此,您可能只是使用以下代码打印数字 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++ );
        }
    }
}

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 couldevent change in the middle of your loop. If you can't rely on xhaving 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?

但实际上,如果该类中的其他代码更改了 x 的值,您最终可能会打印 230498 - 230508。 x 的值可能会在循环中间发生事件更改。如果您不能依赖x某个值或保留您之前分配给它的值,那么在您的代码中使用它就变得徒劳了。如果变量的内容可以立即更改,为什么要使用变量?

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 xfrom another thread, but then why not make it finalin 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.

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