【问题标题】:Threads: Local variable defined in an enclosing scope must be final or effectively final线程:在封闭范围中定义的局部变量必须是最终的或有效的最终
【发布时间】:2016-04-10 14:08:40
【问题描述】:

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

public void stopResolutionProcess() {
    stop = true;
}

这是执行大流程的调用:

boolean solutionFound = tournament.solve();

所以在此之前,我需要运行一个辅助线程来调用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
        }
    }
});

但我在最后一行出现错误。它说:

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

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

【问题讨论】:

  • 如错误提示,您应该将其设为final 或将值复制到最终变量中。
  • “在封闭作用域中定义的局部变量 tournament 必须是最终的或有效的最终” 因此,tournament 变量声明将很明显包含在问题。

标签: java multithreading scope


【解决方案1】:

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

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");

那么你希望这里有什么输出?类似的东西:

MyString
MyString
AnotherString
AnotherString
AnotherString

问题是您不知道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");

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

MyString
MyString
MyString
MyString
MyString

【讨论】:

    【解决方案2】:

    您的问题本身就是您所问问题的答案。

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

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

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

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

    我在下面引用另一个相关问题的答案:Local variable needs to be declared final

    box 的值是对你自己(和编译器)的承诺 在封闭范围内不会改变。编译器会告诉你,如果你 打破这个承诺。

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

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

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

    第 1 行、第 2 行、第 3 行(只是创建匿名类的对象)、第 5 行。稍后调用匿名类创建的对象上的方法时会执行第 4 行。

    【讨论】:

      猜你喜欢
      • 2017-08-28
      • 2019-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-04
      • 1970-01-01
      • 2021-03-31
      相关资源
      最近更新 更多