2010-02-19 64 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

我同意,你應該與贖回和FutureTask去。

但可能沒有必要使用Executor:如果您不打算與其他代碼共享該Executor,則需要創建它的三條線,提交任務,然後再關閉它,似乎過於冗長。你可以使用一個線程。

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