java 线程:在封闭范围内定义的局部变量必须是最终的或有效的最终的

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36530790/
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-11-03 01:34:16  来源:igfitidea点击:

Threads: Local variable defined in an enclosing scope must be final or effectively final

javamultithreadingscope

提问by dabadaba

I have my main class running in the mainmethod. It runs a process that potentially takes a huge amount of time to complete, so I created another method to stop that process: it simply raises a flag that makes the whole process stop:

我的主类在该main方法中运行。它运行一个可能需要大量时间才能完成的进程,因此我创建了另一种方法来停止该进程:它只是引发一个标志,使整个进程停止:

public void stopResolutionProcess() {
    stop = true;
}

This is the call that executes the big process:

这是执行大进程的调用:

boolean solutionFound = tournament.solve();

So right before it, I need to run a secondary thread to call stopResolutionProcess():

所以就在它之前,我需要运行一个辅助线程来调用stopResolutionProcess()

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Stop resolution process? (Y/N): ");
        String answer = sc.next();
        if (answer.equalsIgnoreCase("y")) {
            tournament.getSolver().stopResolutionProcess(); // error here
        }
    }
});

But I am getting an error in the last line. It says:

但我在最后一行收到错误。它说:

Local variable tournament defined in an enclosing scope must be final or effectively final

在封闭范围内定义的局部变量锦标赛必须是最终的或有效的最终

What approach should I take to solve this problem in order to test the method that stops the process?

为了测试停止进程的方法,我应该采取什么方法来解决这个问题?

回答by MalaKa

So what is the problem.. a small example

那么有什么问题..一个小例子

String myString = new String("MyString");
Thread thr = new Thread() {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(myString);
        }
    }
}
thr.start();
myString = new String("AnotherString");

So what output would you expect here? Something like:

那么你期望这里的输出是什么?就像是:

MyString
MyString
AnotherString
AnotherString
AnotherString

The problem is that you don't know when the myStringvariable is changed. This could happen after it was printed 0 times, after being printed 5 times or any time in between. Or in other words, this is not predictable and is very unlikely to be intended.
In order to have a defined behaviour, the variable you use in the Thread needs to be final:

问题是您不知道myString变量何时更改。这可能发生在它被打印 0 次之后、被打印 5 次之后或两者之间的任何时间之后。或者换句话说,这是不可预测的,也不太可能是有意的。
为了有一个定义的行为,你在线程中使用的变量需要是最终的:

final String myString = new String("MyString");
Thread thr = new Thread() {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(myString);
        }
    }
}
thr.start();
// now this following line is not valid anymore and will lead to a compile error
myString = new String("AnotherString");

Now we have a defined behaviour and we know that the output will be:

现在我们有一个定义的行为,我们知道输出将是:

MyString
MyString
MyString
MyString
MyString

回答by nits.kk

Your question itself has the answer to what you have asked.

你的问题本身就有你所问的答案。

Local variable tournament defined in an enclosing scope must be final or effectively final

在封闭范围内定义的局部变量锦标赛必须是最终的或有效的最终

If anonymous class is created inside any method then all the local variables defined in the method but outside the body of the anonymous class should be made final in case they are needed to be used in anonymous class.

如果匿名类是在任何方法内创建的,那么所有在方法中定义但在匿名类主体之外的局部变量都应该是最终的,以防需要在匿名类中使用它们。

public class OuterClass{
    int x,y;
    public void someMethod(){

         final int neededByAnonymousClass = x + y + 30;

         Runnable runnable = new Runnable(){
              // This is like we are creating a class which simply implements Runnable interface.
              // Scope of this class is inside the method someMethod()
              // run() method may be executed sometime later after the execution of someMethod() has completed.
             // all the local variables needs to be final in order they can be used later in time when run() gets executed.

             public void run(){
                 System.out.println(neededByAnonymousClass+ 40);
             }
         }
         Thread thread = new Thread(runnable); // passing the object of anonymous class, created above
         thread.start();
    }
}

So just make your all the local variables (defiend inside the scope of a method) as final which you wish to use inside the run() method of your local anonymous class (class without name). In case you wish to modify the value of a variable then do modifications first and then create the anonymous class. Create another final variable and initialize it with the modified value and use the same in the anonymous class.

因此,只需将您希望在本地匿名类(没有名称的类)的 run() 方法中使用的所有局部变量(在方法范围内定义)作为最终变量。如果您希望修改变量的值,请先进行修改,然后创建匿名类。创建另一个最终变量并使用修改后的值对其进行初始化,并在匿名类中使用相同的值。

I quote below from answer of another related question : Local variable needs to be declared final

我在下面引用另一个相关问题的答案:局部变量需要声明为最终的

It's a promise to yourself (and to the compiler) that the value of box won't change in the enclosing scope. The compiler will tell you if you break that promise.

这是对您自己(和编译器)的承诺,即 box 的值不会在封闭范围内改变。编译器会告诉你是否违反了这个承诺。

The variable value will be used some time later after the execution of the method is completed. Hence local variables must be declared as final. The methods in the anonymous object are not executed in order they are written (sequentially)

变量值将在方法执行完成后的一段时间后使用。因此局部变量必须声明为final。匿名对象中的方法不是按编写顺序执行的(顺序)

Suppose below lines of code where we have a method : methodA() and it contains definition of an anonymous class.

假设在下面的代码行中有一个方法:methodA(),它包含匿名类的定义。

[ line-1 : method A, line-2 method A, line-3 : anonymous class , Line 4 method of anonymous class, line 5 method A ] ==> Order of execution

[第1行:方法A,第2行方法A,第3行:匿名类,匿名类第4行方法,第5行方法A] ==>执行顺序

Line 1, Line 2, Line 3 (just the object creation of the anonymous class), Line 5. Line 4 will be executed later when method on the object created of anonymous class is invoked.

Line 1, Line 2, Line 3 (只是匿名类的对象创建), Line 5. Line 4将在稍后调用匿名类创建的对象上的方法时执行。