开发者

Access outer variable from inner anonymous Runnable

The following example code (SSCCE) complains that local variable a must be final.

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 {}
}

To make things working i change the code to that one

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) {开发者_Python百科 this.x = x; }

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

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

My questions:

  1. Is there something wrong with this ?
  2. The ObjectRef class exists as standard class in JSE ?
  3. What is the right way ?


Right way is using FutureTask and Callable

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


Did you consider using Callable instead? Callable can be used when you produce a result, which seem to be your case.

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


I agree that you should go with Callable and FutureTask.

But it may not be necessary to use an Executor: If you are not going to share that Executor with other code, the three lines required to create it, submit the task, and then shut it down again, seem too verbose. You could just use a Thread.

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

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜