2010-02-19 2 views
3

В следующем примере кода (SSCCE) сообщается, что локальная переменная a должна быть окончательной.Доступ к внешней переменной из внутреннего анонимного Runnable

public class Foo { 

    final List<A> list = new ArrayList() {{ add(new A()); }}; 

    void foo() { 
     A a; 
     Thread t = new Thread(new Runnable() { 
      public void run() { 
       a = list.get(0); // not good ! 
      } 
     }); 
     t.start(); 
     t.join(0); 
     System.out.println(a); 
    } 

    class A {} 
} 

Для того, чтобы все работало я изменить код для того, что один

public class Foo { 

    final List<A> list = new ArrayList() {{ add(new A()); }}; 

    void foo() { 

     // A a; 
     final ObjectRef x = new ObjectRef(); 
     Thread t = new Thread(new Runnable() { 

      public void run() { 
       // a = list.get(0); 
       x.set(list.get(0)); 
      } 

     }); 
     t.start(); 
     t.join(0); 

     // System.out.println(a); 
     System.out.println(x.get()); 
    } 

    class A {} 

    class ObjectRef<T> { 
     T x; 

     public ObjectRef() {} 

     public ObjectRef(T x) { this.x = x; } 

     public void set(T x) { this.x = x; } 

     public T get() { return x; } 
    } 
} 

Мои вопросы:

  1. там что-то не так с этим?
  2. Класс ObjectRef существует как стандартный класс в JSE?
  3. Каков правильный путь?

ответ

3

Вы считаете вместо этого использовать Callable? Callable можно использовать, когда вы производите результат, который, кажется, ваш случай.

final List<A> list = new ArrayList() {{ add(new A()); }}; 

    void foo() { 

     Callable<A> call = new Callable<A> { 
      A call() throws Exception 
      { 
       // do something with the list 
       return list.get(0); 
      } 
     } 

     ExecutorService executor = new ScheduledThreadPoolExecutor(1); 
     Future<A> future = executor.submit(call); 

     System.out.println(future.get()); 
    } 
4

Правильный способ использует FutureTask и отзывной

FutureTask task = new FutureTask(new Callable<A>() { 
    public A call() { 
     return list.get(0); 
    } 
}); 

Executor ex = Executors.newFixedThreadPool(1); 
ex.execute(task); 

// do something else, code is executing in different thread 

A a = task.get(); //get result of execution, will wait if it's not finished yet 


ex.shutdown(); 
+0

не забывайте 'ex.shutdown()' – Thilo

2

Я согласен, что вы должны пойти с Callable и FutureTask.

Но нет необходимости использовать Исполнителя: Если вы не собираетесь делиться этим Исполнителем с другим кодом, три строки, необходимые для его создания, отправить задание, а затем снова закрыть его, показаться слишком подробным , Вы могли бы просто использовать Thread.

FutureTask<A> task = new FutureTask(new Callable<A>() { 
    public A call() { 
     return list.get(0); 
    } 
}); 
new Thread(task).start(); 
A result = task.get(); 
Смежные вопросы