2

My question is why I should use final to decorate the variable, list? It is used by the instance of an anonymous inner class Without final, it won't compile.

the code looks like this:

public class TwoThreadsOneListCurrModi
{
  public static void main(String[] args)
  {    
     final List<String> list = Collections.synchronizedList(new ArrayList<String>());

    for (int i =0 ; i<20;i++)
      list.add(String.valueOf(i));
    Thread t1 = new Thread(new Runnable(){

      @Override
      public void run()
      {
          synchronize(list) {
          System.out.println("size of list:" +list.size());
          }
      }
    });

    t1.start();  
  }
}

But if I use normal class, it is fine.

public class TwoThreadsOneListCurrModi2

{
  public static void main(String[] args)
  {    
     final List<String> list = Collections.synchronizedList(new ArrayList<String>());
    initialize list;

    Thread t1 = new WorkThread(list);
    Thread t2 = new WorkThread(list);    
    t1.start();  
    t2.start();
  }
}
class WorkThread extends Thread{
    List<String> list;
    public void run(){
       do sth with list and synchronize block on list
  }
  Work1(List<String> list)
  {    this.list = list;  }
}
Adam Arold
  • 29,285
  • 22
  • 112
  • 207

1 Answers1

11

This has nothing to do with multithreading. It is there because you are trying to access list from an anonymous inner class' method. Java will always sign an error in this case.

In your case you are creating an anonymous instance of Runnable here by using the new keyword. Everything you are trying to dereference from run will need to be final.

If you are curious about the necessity of the final keyword you can check Jon Skeet's exhaustive answer which explains it in depth.

The point is that when you create an instance of an anonymous inner class, any variables which are used within that class have their values copied in via the autogenerated constructor and it would look odd if the variable could be modified by the rest of the method and vica versa.

Community
  • 1
  • 1
Adam Arold
  • 29,285
  • 22
  • 112
  • 207
  • 3
    You might want to mention the ways behind the need for the variable to be final, about Java creating a copy of the variable before giving it to the anonymous inner class, etc... – Hovercraft Full Of Eels Jul 21 '13 at 20:55
  • 1
    And if it wasn't final, this would imply closure-like behavior, which Java doesn't support. – Cephalopod Jul 21 '13 at 21:00
  • Java doesn't support it....yet. – Adam Arold Jul 21 '13 at 21:04
  • 2
    Your quote in the answer is incorrect and has almost achieved urban legend status in the Java community. It has nothing to do with local variables being cleaned from the stack. Java objects are created on the heap, not the stack, and primitives are simply values which are passed. Rather it has all to do with with lack of closures in Java and Java's need to copy variables before passing them into anonymous classes. Please read [Jon Skeet's answer on the subject](http://stackoverflow.com/a/4732617/522444) and quote him if you're going to quote anyone. – Hovercraft Full Of Eels Jul 21 '13 at 21:17
  • Please correct so I can change my -1 vote back to a +1 vote. – Hovercraft Full Of Eels Jul 21 '13 at 21:24
  • Oh, I see, my bad. I was not sure of it either so I did a little research. Found the wrong answer though. – Adam Arold Jul 21 '13 at 22:05
  • thx a lot. especially for the reference of those articles about this issue. – user2604791 Jul 21 '13 at 23:40