简体   繁体   English

从内部匿名Runnable访问外部变量

[英]Access outer variable from inner anonymous Runnable

The following example code (SSCCE) complains that local variable a must be final. 以下示例代码(SSCCE)抱怨局部变量a必须是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) { 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 ? ObjectRef类在JSE中作为标准类存在吗?
  3. What is the right way ? 什么是正确的方法?

Right way is using FutureTask and Callable 正确的方法是使用FutureTask和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 Callable can be used when you produce a result, which seem to be your case. 当你产生一个结果时,可以使用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() );
    }

I agree that you should go with Callable and FutureTask. 我同意你应该使用Callable和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. 但是可能没有必要使用Executor:如果你不打算与其他代码共享该Executor,那么创建它,提交任务然后再将其关闭所需的三行似乎过于冗长。 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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM