我想知道如何在Java中调用跨线程的不同函数。现在,我正在这样做的方式是将我的线程的run()函数编写为
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 :(得分:4)
我想在这里,实现这一目标的最简单和CPU友好的方法是
public void run() {
while(true) {
synchronized(foo) {
while(!invokeMyFunction) {
foo.wait();
}
}
MyFunction();
invokeMyFunction = false;
}
}
上面的代码在它自己的Thread中运行。另一个线程可以这样做让第一个Thread运行MyFunction():
invokeMyFunction = true;
foo.notifyAll();
请注意 a)你不能使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实现的实现文档,以查看您的队列是否有限制。在任何情况下,请确保您没有添加更多项目,而不是处理太久。
答案 1 :(得分:2)
您可以在线程中放置一个监视器,然后在该监视器上等待。当你调用这个函数时,告诉监视器释放一个人(它应该只有那个人)可以运行你的函数,然后再回去等待。
另一方面,睡眠路线也没有任何内在错误。我明白为什么你会把它称之为凌乱,但它犯了一个愚蠢错误的机会较低,并且提供了你服务之间更松散的耦合。
(旁注 - 你不需要在线程中放置一个监视器。你可以使用该对象作为监视器而不是内部监视器。但是你可以将自己打开给可能干扰它的其他人,所以它是最好使用私有内部对象作为监视器。)
答案 2 :(得分:2)
您的代码中有几个漏洞,除了您要占用CPU之外。
如果您的其他线程希望此线程在MyFunction
执行所需的时间内调用两次,该怎么办?你最终会错过一次调用。
改进可能是:
public volatile boolean invokeMyFunction = false;
public void run() {
while(true) {
if(invokeMyFunction) {
// Moved here.
invokeMyFunction = false;
MyFunction();
}
}
}
但是,这只会降低竞争条件,而不是不可能。
您可能最好使用BlockingQueue
,就像我建议here一样。让另一个线程在这个线程读取的队列中发布一些东西。你也不会那样占用cpu。
答案 3 :(得分:1)
你的计划对我来说很奇怪。为什么要开始一个线程,但要等到未来的某个未知时间才会被告知要运行?为什么不在以后开始呢?
编辑添加以澄清为glowcoder
编辑删除 - 我的不好,我误解了他的问题,他希望能够多次调用MyFunction。在这种情况下,他应该使用其他答案中建议的某种队列