代码之家  ›  专栏  ›  技术社区  ›  Lydon Ch

线程run()方法中的最终枚举

  •  2
  • Lydon Ch  · 技术社区  · 15 年前

    为什么ELVIS ELVIS定义必须是最终的才能在thread run()方法中使用?

     Elvis elvis = Elvis.INSTANCE; // ----> should be final Elvis elvis = Elvis.INSTANCE
     elvis.sing(4);
    
     Thread t1 = new Thread(
       new Runnable() {
       @Override
       public void run() {
       elvis.sing(6); // --------> elvis has to be final to compile
      }
    }
    );
    
    
     public enum Elvis {
       INSTANCE(2);
    
       Elvis() {
         this.x = new AtomicInteger(0);
       }
    
       Elvis(int x){
         this.x = new AtomicInteger(x);
       }
    
       private AtomicInteger x = new AtomicInteger(0);
    
       public int getX() { return x.get(); }
    
       public void setX(int x) {this.x = new AtomicInteger(x);}
    
       public void sing(int x) {
          this.x = new AtomicInteger(x);
          System.out.println("Elvis singing.." + x);
       }
     }
    
    3 回复  |  直到 15 年前
        1
  •  3
  •   Jon Skeet    15 年前

    的值 elvis 匿名内部类正在捕获变量。

    仅Java(当前)捕获变量 按价值 . 编译器要求变量是最终的,这样就不会混淆当 run 在新线程中调用方法:如果更改了 埃尔维斯 在创建新线程之后,但在启动它之前,您希望它做什么?

    这是在C语言和Java中有效地关闭闭包的方式之间的区别。看到我 closures article 了解更多细节。Java 7将使闭包更加简洁——我一直没有遵循,知道是否有任何方式捕获变量本身而不是特定的值。

        2
  •  2
  •   Michael Aaron Safyan    15 年前

    这与线程无关,与构造匿名类无关。问题是,您正在从匿名类中引用局部变量。现在考虑以下内容:

    int c = 5;
    Runnable r = new Runnable(){ public void run(){ System.out.println(c); } };
    c = 6;
    r.run();
    

    在上面的代码片段中,代码应该打印5还是应该打印6?如果R为了解析C而保留对当前堆栈帧的引用,可以想象它可以打印6。也可以想象,它可以提前绑定/捕获c的值并打印5。Java强制你使C最终使这一点完全清楚,同时也可以避免Java挂在当前堆栈框架上的需要。

        3
  •  1
  •   Jason S    15 年前

    这不是你问题的一部分,但我很好奇:如果是原子整数,为什么要重新分配elvis.x?这种方法忽略了atomicinteger的线程安全性。考虑重写:

    public Elvis {
    
       final static private Elvis INSTANCE = new Elvis(2);
       static public Elvis getInstance() { return INSTANCE; }
    
       final private AtomicInteger x; 
    
    
       Elvis() { this(0); }
    
       Elvis(int x){ 
          this.x = new AtomicInteger(x);
       }
    
       public int getX() { return this.x.get(); }
    
       public void setX(int x) {this.x.set(x); }
    
       public void sing(int x) {
          setX(x);
          System.out.println("Elvis singing.." + x);
       }
     }
    

    另外,由于它具有可变内容,因此不应该是枚举。