开发者

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 = 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) {
   开发者_如何学Python   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.

Java only (currently) captures variables by 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?

This is a difference between the way that closures are effectively available in C# and 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.


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? 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.


this isn't part of your question but i'm just curious: why are you reassigning Elvis.x if it's an AtomicInteger? that kind of misses the point of AtomicInteger's thread-safety. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜