【问题标题】:Cross thread function calls with Java使用 Java 进行跨线程函数调用
【发布时间】:2011-12-20 05:46:24
【问题描述】:

我想知道如何在 Java 中跨线程调用不同的函数。现在我这样做的方式是编写我的线程的 run() 函数

public volatile boolean invokeMyFunction = false;

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

如果我想从该线程外部运行函数 MyFunction(),请编写“whateverobject.invokeMyFunction = true”,它将从线程内运行我的函数,因为该循环会拾取它。这对我很有用,但由于那个 while(true) 循环,它使用了我 100% 的 CPU。我可以通过在循环内打一个 Thread.sleep(1000) 来解决这个问题,但这看起来很乱,我不禁相信有更好的方法来做到这一点。

【问题讨论】:

  • 函数调用是否可能不止一个?您是否需要一个可以在第二个线程上调用任意数量函数的解决方案?
  • 理想情况下我会喜欢一个允许在第二个线程上多次调用多个函数的解决方案,是的

标签: java multithreading function


【解决方案1】:

我认为在这里,实现这一目标的最简单且对 CPU 友好的方法是

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

上面的代码在它自己的线程中运行。另一个线程可以这样做,让第一个线程运行 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 实现的实现文档,以查看您的队列是否有限制。在任何情况下,请确保您添加的项目不会超过您可以处理的时间太长。

【讨论】:

  • 优雅且易于实施,正是我想要的 - 谢谢 :)
【解决方案2】:

您可以在线程中放置一个监视器,然后在该监视器上等待。当你调用这个函数时,告诉监视器释放一个可以运行你的函数的人(它应该只有那个人),然后再回去等待。

另一方面,睡眠路线本身也没有任何问题。我明白你为什么称它为混乱,但它犯下愚蠢错误的可能性更低,并且为你的服务之间提供了更松散的耦合。

(旁注 - 您不需要在线程中放置监视器。您可以将该对象用作监视器而不是内部监视器。但是随后您将自己开放给可能干扰它的其他人,所以它是最好使用私有内部对象作为监视器。)

【讨论】:

    【解决方案3】:

    除了你要占用 CPU 之外,你的代码中有几个漏洞。

    如果您的其他线程希望该线程在MyFunction 执行的时间内调用两次怎么办?你最终会错过一次调用。

    改进可能是:

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

    但是,这只会降低竞争条件的可能性,而不是不可能。

    您最好使用BlockingQueue,就像我建议的here 一样。让另一个线程在该线程读取的队列中发布一些内容。你也不会那样占用cpu。

    【讨论】:

      【解决方案4】:

      你的计划对我来说很奇怪。为什么要启动一个线程,但让它等到将来某个未知的时间才被告知运行?为什么不稍后再开始呢?

      添加编辑以澄清光晕编码器

      EDIT REMOVED - 我的错,我误解了他的问题,他希望能够多次调用 MyFunction。在这种情况下,他应该使用其他答案中建议的某种队列

      【讨论】:

      • 可能其他操作需要一定的时间才能完成,最好不要阻塞主线程。例如,考虑读取提要或套接字通信。
      • 不需要阻塞,你仍然可以在另一个线程中运行另一个操作。在你准备好之前不要开始它。
      • 也许不会,但是你每次都要启动一个新线程,或者使用线程池或执行器服务。我并不完全反对,因为这些都是值得学习的东西,但它们不是问题的范围。
      猜你喜欢
      • 2010-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-02
      相关资源
      最近更新 更多