【问题标题】:How to access a Runnable object by Thread?如何通过 Thread 访问 Runnable 对象?
【发布时间】:2011-01-19 00:36:01
【问题描述】:

可能重复:need-help-returning-object-in-thread-run-method

你好。我有一个实现可运行的类,我有一个列表,存储用该类的不同对象实例化的线程。给定运行它们的线程对象,我如何访问底层对象的属性?这是一个例子:

public class SO {
    public static class TestRunnable implements Runnable {
        public String foo = "hello";

        public void run() {
            foo = "world";
        }
    }

    public static void main(String[] args) {
        Thread t = new Thread(new TestRunnable());
        t.start();
        //How can I get the value of `foo` here?
    }
}

【问题讨论】:

  • 除了不确定您的想法之外,我认为您需要对此进行反思,并确保您的方式没有安全管理器。但是,也许您可​​以更详细地描述您想要实现的目标。
  • 我相信你可以继承Thread 本身并覆盖Thread.run() 而不是传递Runnable。那么foo 将只是Thread 的一个属性。
  • @MatrixFrog:如果 Runnable 类需要子类化其他东西,这是不好的,因为 Java 只允许单继承。据我所知,java.lang.Runnable 的主要目的是通过允许您使用 Thread(java.lang.Runnable) 将线程功能添加到已经继承了其他东西的类来解决这个问题。
  • 老实说,我想不出您想要这样做的任何可能原因。也许你应该问一个不同的问题?

标签: java multithreading concurrency


【解决方案1】:

我在 java.lang.Thread 文档中看不到任何方法。

那么,我的最佳答案是,您可能应该使用List<Runnable> 而不是(或除了)List<Thread>。或者您可能想要某种map 结构,以便您可以从线程访问Runnable。 (例如,java.util.HashMap<java.lang.Thread, java.lang.Runnable>

【讨论】:

  • 你可以使用代码引号直接使用<>'s,用`'s包裹List<Runnable>
  • @Tanzelax:哇哦,我也知道。为什么我没有想到用它来格式化我的代码,我不知道。我只能说,这真是漫长的一天。感谢您的提示。
  • 我对否决票很好奇。谁做的,愿意解释一下吗?
【解决方案2】:

并发库很好地支持了这一点。注意:如果你的任务抛出一个异常,Future 会在你调用 get() 时持有它并抛出一个包装异常

ExecutorService executor = Executors.newSingleThreadedExecutor();

Future<String> future = executor.submit(new Callable<String>() { 
   public String call() { 
      return "world"; 
   } 
}); 

String result = future.get(); 

【讨论】:

  • 你可能想在之后关闭执行器。
【解决方案3】:
TestRunnable r = new TestRunnable();
Thread t = new Thread(r);
t.start();
//there you need to wait until thread is finished, or just a simple Thread.sleep(1000); at this case
System.out.println(r.foo);

顺便说一句,在实际情况下您需要使用CallableFutureTask

【讨论】:

  • 总之,没有办法做到,对吧?您需要保留对 Thread 和 Runnable 的引用。如果您能证实您关于需要 Callable 和 FutureTask 的说法,我将不胜感激。
  • 是的,您需要引用您正在运行的对象并将结果返回给您,在这种情况下为RunnableCallableFutureTask 是做你想做的事情的更合适的方式。
  • 我想我只是没看到。
【解决方案4】:

如果要返回异步计算的值,看Callable和FutureTask:

FutureTask<String> task = new FutureTask(new Callable<String>() {
   public String call() {
      return "world";
   }
});
new Thread(task).start();
String result = task.get();

【讨论】:

    【解决方案5】:

    我遇到了同样的问题。这是我的解决方案:

    public static class TestRunnable implements Runnable {
        public String foo = "hello";
    
        public void run() {
            foo = "world";
        }
    
    public static void main(String[] args) {
        TestRunnable runobject = new TestRunnable();
        Thread t = new Thread(runobject);
        runobject.foo;  //The variable from runnable. hello;
        t.start();
        runobject.foo;  //The variable from runnable. world;
    }
    

    【讨论】:

      【解决方案6】:

      我认为总的来说你可以/应该避免这样做,但如果你真的需要这样做,不应该像 MatrixFrog 的建议工作(未经测试):

      class RunnableReferencingThread extends Thread {
          public final Runnable runnable;
          public RunnableReferencingThread(Runnable r) {
              super(r);
              this.runnable = r;
          }
      }
      

      ?

      【讨论】:

      • 那不会像写的那样编译。
      • @gerardw:我刚刚提交了一个应该纠正这个问题的编辑(交换构造函数的两个语句,这样超级调用将是构造函数的第一个语句)
      【解决方案7】:

      这就是你可以直接实现它的方式。

      public static void main(String[] args) {
          // Keep a reference to the runnable object for later ...
          TestRunnable r = new TestRunnable();
          Thread t = new Thread(r);
          t.start();
          // Wait until the child thread has finished
          t.join();
          // Pull the result out of the runnable.
          System.out.println(r.foo);
      }
      

      但是,现代(不易出错)的方法是使用java.util.concurrent 中的更高级别的并发类。

      【讨论】:

        【解决方案8】:

        如果您的线程有状态信息,请忘记 Runnable 并简单地扩展 Thread,覆盖 run 方法。

        【讨论】:

          【解决方案9】:

          你可以继承 Thread,并添加你需要的方法。由于 Thread 的一些令人讨厌的实现细节,您必须保留自己的目标 Runnable 副本并覆盖用于创建 Thread 的所有 Thread 构造函数。

          【讨论】:

            【解决方案10】:

            举一个 Paul Crowley 解决方案的具体例子,我认为这是他的建议:

            public class BackgroundJob<JOB extends Runnable> extends Thread {
            
                private final JOB mJob;
            
                public BackgroundJob(JOB job) {
                    super(job);
                    mJob = job;
                }
            
                public JOB getJob() {
                    return mJob;
                }
            
            }
            

            【讨论】:

              【解决方案11】:

              我想,如果可以的话,就是扭转局面。那么在这种情况下,一个好的解决方案是将线程存储在您的可运行类中。你的runnable有一个start()函数,它启动并启动本地线程并调用thread.start。像这样,您可以拥有线程对象的列表。你也可以有一个访问器来获取线程。

              public class Threaded extends other implements Runnable {
                  Thread localThread;
              
                  @Override
                  public void run() {
                      //...
                  }
              
                  public void start() {
                      localThread = new Thread(this);
                      localThread.start();
                  }
              
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2013-11-22
                • 2015-04-11
                • 2017-05-28
                • 1970-01-01
                • 2019-08-08
                • 1970-01-01
                • 2015-04-01
                相关资源
                最近更新 更多