简体   繁体   English

Thread的run()方法中的最终枚举

[英]Final enum in Thread's run() method

Why is the Elvis elvis definition has to be final to be used inside the Thread run() method? 为什么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);
   }
 }

The value of the elvis variable is being captured by the anonymous inner class. elvis变量的值由匿名内部类捕获。

Java only (currently) captures variables by value . 仅Java(当前) 按value捕获变量。 The compiler requires that the variable is final so that there can be no confusion about what will actually be used when the run method is called in the new thread: if you changed the value of elvis after creating the new thread but before starting it, what would you expect it to do? 编译器要求变量是最终变量,以便不会混淆在新线程中调用run方法时实际使用的内容:如果在创建新线程之后但启动之前更改了elvis的值,该怎么办?您希望它能做到吗?

This is a difference between the way that closures are effectively available in C# and Java. 这是在C#和Java中有效使用闭包的方式之间的区别。 See my closures article for more details of this. 有关更多详细信息,请参见我的关闭文章 Java 7 will make closures more concise - I haven't been following along to know whether there will be any way of capturing the variable itself rather than a particular value. Java 7将使闭包更加简洁-我一直没有跟进来了解是否有任何方法可以捕获变量本身而不是特定值。

This has nothing to do with threads and everything to do with constructing anonymous classes. 这与线程无关,与构造匿名类无关。 The issue is that you are referencing a local variable from within the anonymous class. 问题是您要从匿名类中引用局部变量。 Now consider the following: 现在考虑以下几点:

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

In the snippet above, should the code print 5 or should it print 6? 在上面的代码段中,代码应打印5还是应打印6? If r were to hold onto a reference to the current stack frame in order to resolve c, it is conceivable that it could print 6. It is also conceivable that it could bind/capture the value of c earlier and print a 5. Java forces you to make c final so as to make this completely clear and also to absolve Java of the need to hang onto the current stack frame. 如果r保留对当前堆栈帧的引用以便解析c,则可以想象它可以打印出6。也可以想象,它可以更早地绑定/捕获c的值并打印出5。您可以使c为final,以便使其完全清楚,也可以免除Java挂在当前堆栈框架上的需要。

this isn't part of your question but i'm just curious: why are you reassigning Elvis.x if it's an AtomicInteger? 这不是您的问题的一部分,但我很好奇:如果它是AtomicInteger,为什么还要重新分配Elvis.x? that kind of misses the point of AtomicInteger's thread-safety. 这种错失了AtomicInteger的线程安全性。 Consider rewriting: 考虑重写:

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

also since this has mutable content, it shouldn't be an enum. 而且因为它具有可变的内容,所以不应该是枚举。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM