【问题标题】:A "starvation-free" implementation in JavaJava 中的“无饥饿”实现
【发布时间】:2017-08-30 18:25:43
【问题描述】:

在为工作线程使用简单的互斥量和条件变量时,我的程序会遇到一些罕见且零星的线程饥饿错误,我想防止这种情况发生。

以下是我正在做的一个简单示例。有 4 个工作线程调用“Producer”,一个主线程调用 prod.getTasks()。

此代码“无死锁”,但由于错误,显然不是“无饥饿”。

当我得到 检测到线程不足或时钟跳跃(管家 delta=1m18s317ms137µs765ns) 错误时:

A) 因为生产者线程处于等待状态的时间过长? (我不这么认为,因为我相信线程可以等待任意时间才能准备好使用。肯定超过 1 分钟)。

B) 因为其中一个等待的工作线程已被传递太多次?

基本上,任何有助于消除饥饿的好建议都会受到赞赏。

class Producer implements Runnable
{
    private static ArrayList<Task> arrTasks = new ArrayList<Task>();

    void getTasks()
    {
        Task t = getTask(); // get Tasks from a producer specific recordset.    
        synchronized (arrTasks)
        {
            arrTasks.add(t);
            arrTasks.notify();
        }
    }

    void run()
    {
        while (true) 
        {
            Task t = null;

            synchronized (arrTasks)
            {
                if (arrTasks.size() == 0)
                    arrTasks.wait();

                if (arrTasks.size() > 0)
                    t = arrTasks.remove(0);
            }

            if (t != null)
                processTask(t);

            if (mExit) 
                break;
        }
    }
}

【问题讨论】:

  • 代码不完整。 s_ptTasks 是什么?此外,您 wait() 在一个对象上,notify() 在另一个对象上。这样可以吗?
  • @RomanPuchkovskiy:我的错……我编辑了它。
  • @NathanHughes 这是对实际代码的简化,它确实正确使用了受保护的块。我也知道我可以使用更高级别的服务来处理并发。这只是一个关于饥饿的问题。
  • 你为什么不使用阻塞队列?它将为您进行同步,ArrayBlockingQueue 至少有一个带有fair 选项。 (所以不会饿死单个消费者)
  • 我刚刚编辑了代码以更准确地表示真实代码。 Worker 实际处理一个任务,然后检查消费者是否落后,如果落后则等待。

标签: java multithreading concurrency mutex condition-variable


【解决方案1】:

生产者/消费者模式总是要么饿死,要么超载,要么毫无意义。这不是性能模式,它用于抽象。

如果你使用concurrent BlockingQueue,你的代码可以变得更容易,它可以删除你所有的synchronized

【讨论】:

  • 实际的实现既不超载,也不无意义,也不总是饿死。它每晚有效地运行数百万条记录,只有一次显示饥饿。如果 BlockingQueue 也使用 Guarded Blocks,我也不会感到惊讶。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-12
  • 2012-07-26
  • 1970-01-01
相关资源
最近更新 更多