0

我正在尝试在 java 中创建一个池对象的类。该类开始创建所需的最小数量的对象,当请求开始时,每个线程检查是否有可用的对象,是否可以创建它,因为尚未达到最大值,否则它必须等待得到一个。

这个想法是线程需要同步以获取/创建引擎,但它们可以并行处理(ProcessWithEngine方法)。处理可能需要几分钟,显然它正在按我的意愿工作。

问题是,有时.notify()被调用并从 释放线程时.wait(),队列有 0 个项目,这应该是不可能的,因为就在 之前.notify(),添加了一个项目。

可能是什么问题呢?

代码是这样的:

Queue _queue = new Queue();

int _poolMax = 4;
int _poolMin = 1;
int _poolCurrent =0;


public void Process(Object[] parameters) throws Exception
{
    Engine engine = null;

    synchronized(_queue) 
    {
        if(_queue.isEmpty() && _poolCurrent >= _poolMax)
        { 
            _queue.wait();

            // HERE : sometimes _queue.isEmpty() is true at this point.

            engine = (SpreadsheetEngine)_queue.dequeue();

        }
        else if (_queue.isEmpty() && _poolCurrent < _poolMax)
        {               
            engine = CreateEngine();
            _poolCurrent++;
        }
        else
        {               
            engine = (Engine)_queue.dequeue();
        }   
    }

    ProcessWithEngine(engine, parameters);


    // work done
    synchronized(_queue) 
    {
        _queue.enqueue(engine);

        _queue.notify();
    }
}

我已经解决了这个问题:

            do
            {
                _queue.wait();

            }
            while(_queue.isEmpty());

但基本上这意味着一个线程正在失去它的轮次,这可能意味着稍后会超时。

4

3 回答 3

3

所有调用.wait()都必须包含在一个while循环中。调用wait()可以随机唤醒。

根据文档:“在一个参数版本中,中断和虚假唤醒是可能的,并且应该始终在循环中使用此方法:”

于 2011-04-11T14:20:08.403 回答
1

使用您的解决方案,不是每个线程都进入无休止的等待()吗?

正常的成语是这样的:

synchronized(stuff) {
  while (mustWait) 
     wait();
  // do things with stuff
}

另一方面,既然您已经在使用队列,为什么不把它变成一个java.util.concurrent.BlockingQueue并免费获得一个并发解决方案呢?

于 2011-04-11T14:24:19.387 回答
1

至少有两个原因是可能的:

  • 正如 Justin Waugh 所指出的,虚假唤醒
  • 另一个线程获取锁并dequeue()在两者之间调用 - 在第一个线程调用notify()并完成其synchornized块之后,但在第二个线程实际从其wait(). 这是可能的,因为synchronized//不保证公平wait()notify()

因此wait()应始终在循环内使用:

while (_queue.isEmpty())
    _queue.wait();
于 2011-04-11T14:24:26.410 回答