2010-02-20 74 views
17

可能的重複:need-help-returning-object-in-thread-run-method如何通過線程訪問Runnable對象?

你好。我有一個實現runnable的類,我有一個List,存儲使用該類的不同對象實例化的Threads。如何在給定線程對象運行的情況下訪問底層對象的屬性?這裏是一個例子:

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? 
    } 
} 
+1

除了沒有真正被肯定你有什麼想法,我想你會需要這種反思,也要確保你的方式沒有安全管理員。 但是,也許你可以更詳細地描述你試圖達到的目標。 – 2010-02-20 00:50:02

+0

我相信你可以繼承'Thread'本身並覆蓋'Thread.run()'而不是傳遞'Runnable'。那麼'foo'就是'Thread'的一個屬性。 – MatrixFrog 2010-02-20 00:52:58

+1

@MatrixFrog:如果Runnable類需要繼承其他類,這是不好的,因爲Java只允許單一繼承。據我所知,java.lang.Runnable的主要目的是通過允許使用Thread(java.lang.Runnable)將線程功能添加到已經具有其他子類的類來解決此問題。 – 2010-02-20 00:56:05

回答

12

我沒有看到任何方式在java.lang.Thread文檔中做到這一點。

我的最佳答案是,您可能應該使用List<Runnable>而不是(或除了)List<Thread>。或者您可能需要某種map結構,以便您可以從線程訪問Runnable。 (例如,java.util.HashMap<java.lang.Thread, java.lang.Runnable>

+0

你可以直接使用代碼引用來使用''''',把'List '換成'' – Tanzelax 2010-02-20 01:07:08

+0

@Tanzelax:哦,哇,我也知道。爲什麼我沒有想到用它來格式化我的代碼,我不知道。我只能說,這是一個非常漫長的一天。謝謝你的提示。 – 2010-02-20 01:49:45

+0

我很好奇downvote。誰做的,關心解釋? – 2010-02-20 04:09:37

4
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

+2

因此總而言之,這是無法完成的,對吧?您需要保持對Thread和Runnable的引用。 如果您能證實您需要Callable和FutureTask的聲明,我將不勝感激。 – 2010-02-20 01:02:01

+0

是的,你需要一個對你運行的對象的引用,並且返回結果給你,在這種情況下是'Runnable'。 'Callable'和'FutureTask'是更適合你做事情的方法。 – 2010-02-20 01:10:56

+2

我想我只是沒有看到它。 – 2010-02-20 01:50:39

1

這是你如何能直接實現這一點。

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使用更高級別的併發類。

4

如果你想返回一個異步計算的值,看看可贖回和FutureTask:

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

併發庫支持這一點。注意:如果您的任務拋出一個異常,未來將持有這一點,並拋出一個包裝異常,當你調用get()

ExecutorService executor = Executors.newSingleThreadedExecutor(); 

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

String result = future.get(); 
+2

之後您可能想關閉執行程序。 – Thilo 2010-02-20 12:23:40

2

我想一般,你可以/應該避免這樣做,但如果你真的需要做它應該不像MatrixFrog的建議工作(未經測試):

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

+0

這不會按照書面進行編譯。 – gerardw 2014-03-13 19:38:52

+0

@gerardw:我剛剛提交了一個應該糾正的編輯(交換構造函數的兩個語句,使得超級調用將成爲構造函數的第一條語句) – 2014-11-07 20:09:51

0

你可以繼承Thread,並添加你需要的方法。您必須保留自己的目標Runnable副本並覆蓋所有用於創建線程的線程構造函數,因爲線程的一些惱人的實現細節。

1

我有同樣的問題。這裏是我的解決方案:

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; 
} 
1

如果你的線程有狀態信息,忘記Runnable,只是擴展Thread,覆蓋run方法。

1

爲了讓保羅·克勞利的解決一個具體的例子,我覺得這是他建議:

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

}