【问题标题】:How to avoid busy spinning in Java如何避免在 Java 中忙于旋转
【发布时间】:2014-12-20 00:07:14
【问题描述】:

我有一个多线程应用程序,其中一个线程将消息发送到另一个线程。等待线程轮询消息并做出反应(处理锁)。像这样:

等待线程代码:

while(true)
{
  if(helloArrived())
    System.out.println("Got hello");
  if(byeArrived())
    System.out.println("Got bye");
  if(stopArrived())
    break;
}

我想避免这种占用 CPU 的技术并改用其他方法。有什么想法吗?

编辑:实际代码如下:

BlockingQueue<Mail> killMeMailbox = new LinkedBlockingQueue<Mail>();
BlockingQueue<Mail> messageMailbox = new LinkedBlockingQueue<Mail>();

public void run()
    {
        while(true)
        {
            if(killMeMailbox.size() > 0)
            {
                break;
            }
            if(messageMailbox.size() > 0)
            {
              System.out.println(messageMailbox.poll());
            }
        }
     }

public void receiveMail(Mail mail)
    {
        //kill
        if(mail.from == -1)
        {
            killMeMailbox.add(0);
        }
        else
        {
            //other
            try
            {
                messageMailbox.put(mail);
            }
            catch(Exception e)
            {
                System.out.println(e.getMessage());
            }
        }
    }

【问题讨论】:

  • 生产者消费者问题。你试过你的朋友谷歌吗?
  • 你需要一个消息队列。您可以使用 BlockingQueue,因此等待线程将被阻塞,直到消息到达。
  • 我实际上正在使用该数据结构。但我正在检查函数的大小并将其清除为句柄。有错吗?
  • @Josh 在您使用队列的位置显示您的代码。

标签: java multithreading mutex


【解决方案1】:

您是否尝试过放置一些 Thread.sleep 以避免不断执行 while 循环?它将为您的其他线程释放 CPU 并避免占用空间

http://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html

【讨论】:

  • 虽然在某些情况下使用sleep 可能有效,但出于响应性原因,使用notifyAll()/wait() 更好。
  • 然后只需稍作休眠或使用其他数据结构。我认为有一些像 BlockingQueue 这样的结构允许线程等待队列中的某些东西
【解决方案2】:

如果您可以根据任务执行器重新表述您的问题,请考虑使用SingleThreadExecutor。如果您需要更奇特的东西 - a concurrent queue 甚至 wait()/notify()

【讨论】:

    【解决方案3】:

    避免这种情况的正确方法是使用java.lang.Object 实现的等待/通知机制,或Java 类库提供的更高级别的并发机制之一:

    (选择最适合您的特定用例的机制...)


    使用Thread.sleep 不是一个好的解决方案。虽然您减少了 CPU 负载(与轮询循环相比),但另一方面是您降低了响应能力。


    我现在正在使用 BlockingQueue。但也许我做错了。我刚刚添加了上面的实际代码。你看到我的问题了吗?

    是的。您正在以一种旨在避免阻塞的方式使用队列。那是错误的做法。你应该使用take()(它会阻塞直到有条目可用)而不是poll(),并去掉测试队列大小的代码。

    您的“killMeMailbox”似乎旨在让您停止等待邮件。您应该能够使用Thread.interrupt 来实现它。 (中断将解除对take() 调用的阻塞...)

    【讨论】:

    • 我建议提及LockSupport 而不是等待/通知。它是等待/通知的一对一替代品,但不受竞争条件的影响。
    • 我现在正在使用 BlockingQueue。但也许我做错了。我刚刚添加了上面的实际代码。你看到我的问题了吗?
    • @MarkoTopolnik - 我听到你说的,但我不熟悉。我可以建议您添加自己的答案来解释如何使用它。
    • 完美! Take() 是我所缺少的。谢谢!
    • 无论如何,这些机制都太低级了,所以在这里写一个完整的答案是没有意义的。但由于 wait/notify 已被有效弃用(discouraged 是这个词),我不想提及它。
    【解决方案4】:

    你正在做busy waiting。你不应该这样做,因为它会浪费 CPU 周期。等待某个事件的线程或进程应该在blocked state 中。以下是实现此目的的可能方法:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2013-07-12
      • 2013-09-29
      • 1970-01-01
      • 2012-05-08
      相关资源
      最近更新 更多