2011-12-20 105 views
3

我想知道如何在Java中跨線程調用不同的函數。現在我做的方法是寫我的run()我的線程的功能,從而與Java交叉線程函數調用

public volatile boolean invokeMyFunction = false; 

public void run() { 
    while(true) { 
     if(invokeMyFunction) { 
      MyFunction(); 
      invokeMyFunction = false; 
     } 
    } 
} 

,如果我想從一個線程寫入之外運行的功能MyFunction的()「whateverobject.invokeMyFunction =真「,它會從線程內運行我的函數,因爲該循環將會啓動它。這對我來說很好,但是由於(true)循環,它佔用了我100%的CPU。我可以通過在循環內部打一個Thread.sleep(1000)來解決這個問題,但這看起來很麻煩,我忍不住要相信這樣做有更好的方法。

+0

是否有可能會有多個函數調用? 您是否需要可以在第二個線程上調用任意數量函數的解決方案? – Lalaland 2011-12-20 05:58:15

+0

理想情況下,我會喜歡一個允許在第二個線程上多次調用多個函數的解決方案,是的 – Macmee 2011-12-20 18:52:01

回答

4

我想在這裏,實現這一目標的最簡單和CPU友好的方式是

public void run() { 
    while(true) { 
     synchronized(foo) { 
      while(!invokeMyFunction) { 
       foo.wait(); 
      } 
     } 
     MyFunction(); 
     invokeMyFunction = false; 
    } 
} 

上面的代碼在它自己的線程中運行。另一個線程可以做到這一點,讓第一個線程中運行的MyFunction():

invokeMyFunction = true; 
foo.notifyAll(); 

注意 一)你不能讓invokeMyFunction布爾和超過它,因爲在所有的Java :) 只有兩個布爾同步b)如果invokeMyFunction被設置了n次,如果invokeMyFunction設置爲true,它可能仍會運行更少的次數,而不是false。 c)用的BlockingQueue可能會更容易並允許線程1運行任意功能:

while(true) { 
    Runnable next = queue.take(); 
    next.run() 
} 

而另一個線程會告訴它這樣運行的MyFunction:

queue.put(new Runnable() { 
    void run() { 
     MyFunction(); 
    } 
}); 

似乎更容易對我說: )另外,如果您希望n個線程運行通過隊列的任何內容,您只需產生n個在隊列上偵聽的線程。或者你可以學習如何使用線程池:http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html

注:

queue.put()塊,直到一個新的可用空間的BlockingQueue的,即它會阻止如果是「滿」。查看您正在使用的任何BlockingQueue實現的實現文檔,以查看您的隊列是否有限制。在任何情況下,請確保您不需要添加更多項目,而不是處理時間過長。

+0

優雅而簡單的實現,正是我所期待的 - 謝謝:) – Macmee 2011-12-20 23:53:37

2

你可以在你的線程中放置一個監視器,然後等待該監視器。當你調用這個函數時,告訴監視器釋放一個人(並且它應該只有一個人),他們可以運行你的函數,然後再返回等待。

另一方面,睡眠路線本身也沒有錯。我明白了爲什麼你會稱之爲混亂,但它犯了一個愚蠢的錯誤的機會較低,並提供了服務之間的鬆散耦合。 (注意 - 你不需要在線程中放置一個顯示器,你可以使用這個對象作爲顯示器而不是內部顯示器,但是你可以打開自己,直到有可能干擾它的其他人,所以最好使用私人內部對象作爲你的顯示器。)

1

你的計劃對我來說很陌生。爲什麼要啓動一個線程,但要等到未來的某個未知時間才能被告知運行?爲什麼不在以後的時候開始呢?

編輯添加到澄清glowcoder

修改已移除 - 我的壞,我誤解了他的問題,他希望能夠調用MyFunction的多次。在這種情況下,他應該使用某種類型的隊列,如其他答案中所建議的

+0

假設其他操作需要一定的時間來完成,最好不要阻塞主線程。考慮例如閱讀饋送或套接字通信。 – corsiKa 2011-12-20 06:46:08

+0

不需要阻塞,你仍然可以在另一個線程中運行其他操作。只要你準備好就不要開始它。 – user949300 2011-12-20 06:55:30

+0

也許不是,但是您必須每次都啓動一個新線程,或者使用線程池或執行程序服務。我並不完全反對,因爲那些東西是值得學習的,但它們不是問題的範圍。 – corsiKa 2011-12-20 07:10:12

2

代碼中有幾個漏洞,除了你要殺死cpu。

如果您的其他線程想讓此線程在執行MyFunction的時間內調用兩次,該怎麼辦?你最終會失去一個調用。

的改進可能是:

public volatile boolean invokeMyFunction = false; 

public void run() { 
    while(true) { 
     if(invokeMyFunction) { 
      // Moved here. 
      invokeMyFunction = false; 
      MyFunction(); 
     } 
    } 
} 

然而,這不僅使競爭條件不太可能,也不是不可能。

你可能會更好使用BlockingQueue像我建議here。讓另一個線程在由該線程讀取的隊列中發佈一些內容。你也不會用這種方式管理CPU。