2011-12-20 110 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。