2012-10-01 44 views
4

我一直在試圖教自己的併發性,我遇到了一個問題。我知道兩個Java線程可以通過wait()notify()相互通信。然而,這需要一個線程處於非活動狀態,並且基本上「只是坐在」一直到另一個線程喚醒它爲止。兩個線程在兩個運行時如何通信?

是否有可能讓兩個線程同時運行,並仍然讓它們偵聽來自另一個線程的通知?這是通過併發技術來完成的,還是像ActionListener那樣?

例如,我正在測試的項目基本上是一個網格,其中不同的實體在不同的單元中漫遊。當兩個實體碰巧進入同一個單元格時,我希望通知另一個單元格,並在此基礎上發生不同的事情(例如,問候語:「你好!」)。但是就目前而言,在等待/通知範例中,線程/實體之一必須只坐在一個小區中等待另一個小區漫步;他們不能同時移動。

回答

4

有幾種方法可以在線程之間進行通信。使用最常用的方法,您可以使用實例變量在線程之間共享信息,但必須注意只能從一個線程寫入或將任何更新同步到共享變量。或者,您可以使用專爲線程間通信而設計的管道I/O流,或者在線程之間傳遞原始數據。一個線程將信息寫入流中,另一個線程讀取信息。

下面是一個示例方法,它將讀取慢速網絡連接的輸出並使用線程將其轉儲到System.out。

public void threads() throws IOException { 
    final PipedOutputStream outputForMainThread = new PipedOutputStream(); 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      while(moreDataOnNetwork()) { 
       byte[] data = readDataFromNetwork(); 
       try { 
        outputForMainThread.write(data); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }).start(); 
    BufferedReader reader = new BufferedReader(new InputStreamReader(new PipedInputStream(outputForMainThread))); 
    for(String eachLine = reader.readLine(); eachLine != null; eachLine = reader.readLine()) { 
     System.out.println(eachLine); 
    } 
} 

但是它幾乎聽起來像你想去的地方時,其他線程檢測到某個條件一個線程(用戶界面線程)通知事件回調機制。根據你的平臺,大部分內容都被烘焙了。使用Android,例如,你可以有一個線程來確定一個網格實體的移動。它會向主用戶界面線程發送更新以重新繪製屏幕。這樣的更新可能類似於:

public void gridEntityDidUpdate(final Point fromLocation, final Point toLocation) { 
    Activity activity = getMainActivity(); 
    activity.runOnUiThread(
      new Runnable() { 
       @Override 
       public void run() { 
        updateScreen(fromLocation, toLocation); 
        if(pointsAreCoincedent(fromLocation, toLocation)) { 
         System.out.println("Hello there!"); 
        } 
       } 
      } 
    ); 
} 

private void updateScreen(Point fromLocation, Point toLocation) { 
    //Update the main activity screen here 
} 

在這種情況下,你有一個後臺線程的作品了屏幕上的所有元素的位置,並通知當元素位置改變主線程。有一種提取的方法確定2點是否是巧合的或相同的。

+0

很好的回答!然而,我的問題更多的是,我怎麼能得到兩個屏幕上的元素互相溝通,而不是讓他們與用戶界面溝通。 :)我也沒有使用這個項目的GUI,但我理解你的例子的重點。 – asteri

+0

也許可以解釋你當前的代碼。你使用了多少個線程?每個線程負責什麼?這聽起來像你有2個線程,每個線程控制一個單獨的屏幕元素,在這種情況下,你可能會得到一些像每個元素的Point成員變量一樣快/髒的東西。在任一線程執行一個動作之前,它可以檢查另一個線程的成員變量並作出相應的響應。 – Cliff

1

您可以使用Erlang語言安全地傳達其中有自己的地址空間內的Java作爲一個更好的和安全的替代線程一起運行Processes之中。

0

嘗試使用ThreadManager類,其中有List<Thread>,有點像信號量對象。你的線程應該能夠從那裏找到並引用其他線程。

0

是否有可能讓兩個線程同時運行並仍然讓它們偵聽來自另一個線程的通知?

每當他們不在等待時,他們可以同時做某件事。如果他們似乎只是在等待對方,那麼你最好用一個線程。(使用多線程並不總是更好)

這是通過併發技術還是像ActionListener?

這很可能是您如何分解問題的設計問題。當它們之間的交互最少時,線程工作得最好。如果他們高度依賴對方,則應考慮使用較少的線程。

但因爲它的立場,與等待/通知模式,線程/實體的一個具有簡單地坐在一個單元等待另一個徘徊在;

我不明白爲什麼你需要等待/在這裏通知。當他們在同一個單元格中時,我只會讓他們四處移動並互相發送消息。

+0

我知道如果他們沒有在等待,他們都可以做事。問題是如何讓它們在*兩者都在運行時進行通信。從本質上講,如何讓他們「按照你的說法互相發送信息」,而無需等待另一個人這樣做。 – asteri

+0

那麼你需要一個生產者 - 消費者隊列,我想。許多線程圍繞着P-C隊列讀取 - 非常常見的設計。線程間消息排隊直到消費者開始執行它們。 –

+0

我會使用ExecutorService讓線程一起工作。您需要線程池並在需要時更正結果 –

1

我一直在試圖教自己的併發性,我遇到了一個問題。我知道兩個Java線程可以通過wait()和notify()相互通信。

「經典」Java線程教程提前等待/通知。回到Java 1.1,1.2的時間框架就是這樣。但是,如果您可以通過Brian Goetz獲得優秀的「Java併發實踐」的副本,則不會討論等待/通知,直到第四節的第14章「構建自定義同步器」高級主題爲止。我在這裏給出了嚴格的解釋,但是我得到的印象是「如果你已經閱讀了前面300頁,並且迄今爲止所討論的構建塊都不符合你的需求,那麼你可以嘗試使用wait/notify來構建你自己的構建」。

我的觀點是wait/notify雖然很重要,但可能並不是開始學習併發的最佳位置。這個問題中的一些答案/評論(生產者/消費者,ExecutorService)指的是在Java 5中添加的更高級別的併發構建塊。儘管這些內容稍後添加,但這是您應該首先學習的東西。

回到你的問題 - 這裏有一對夫婦的想法:

如果這是一個GUI應用程序,你想有一個後臺線程做了一些工作,檢查SwingWorker。我已經成功地使用了一個SwingWorker(9.3.3節),後臺線程從阻塞隊列中讀取消息(5.3節)可以完成一些工作,並通過調用更高級別的「publish」方法來通知GUI線程。沒有「等待/通知」 - 至少不在我的代碼中。

如果應用程序不是基於Swing的,並且想要讓不同的線程並行執行任務並偶爾向對方發送消息,請考慮ZeroMQ「充當併發框架的套接字庫」。使用ZeroMQ,每個線程都運行一個讀取和處理消息的事件循環。線程可以通過向自己發送消息來安排自己的線程工作。它可以通過向該線程發送消息(套接字)來安排工作/通知不同的線程。不管怎樣,祝你好運。

相關問題