Java 对象池与.wait和.notify

Java 对象池与.wait和.notify,java,multithreading,synchronization,wait,notify,Java,Multithreading,Synchronization,Wait,Notify,我正在尝试用java创建一个类来池对象。该类开始创建所需的最小数量的对象,当请求开始启动时,每个线程检查是否有可用的对象,是否由于尚未达到最大值而可以创建该对象,或者是否必须等待获得一个对象 其思想是线程需要同步以获取/创建引擎,但它们可以并行处理(ProcessWithEnginemethod)。处理过程可能需要几分钟,而且很明显,它正在按照我的要求工作 问题是,有时当调用.notify()并从.wait()中释放线程时,队列中有0个项目,这应该是不可能的,因为就在.notify()之前添加了

我正在尝试用java创建一个类来池对象。该类开始创建所需的最小数量的对象,当请求开始启动时,每个线程检查是否有可用的对象,是否由于尚未达到最大值而可以创建该对象,或者是否必须等待获得一个对象

其思想是线程需要同步以获取/创建引擎,但它们可以并行处理(
ProcessWithEngine
method)。处理过程可能需要几分钟,而且很明显,它正在按照我的要求工作

问题是,有时当调用
.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();
    }
}
synchronized(stuff) {
  while (mustWait) 
     wait();
  // do things with stuff
}
但基本上这意味着线程正在失去轮次,这可能意味着稍后超时。

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

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

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


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

对于您的解决方案,不是每个线程都会进入无休止的等待()

通常的习语是这样的:

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();
    }
}
synchronized(stuff) {
  while (mustWait) 
     wait();
  // do things with stuff
}

另一方面,既然您已经在使用队列,为什么不将其设置为
java.util.concurrent.BlockingQueue
,并免费获得一个并发解决方案?

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

通常的习语是这样的:

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();
    }
}
synchronized(stuff) {
  while (mustWait) 
     wait();
  // do things with stuff
}

另一方面,既然您已经在使用队列,为什么不将其设置为
java.util.concurrent.BlockingQueue
并免费获得并发解决方案呢?

至少有两个原因:

  • 贾斯汀·沃(Justin Waugh)指出的虚假唤醒
  • 另一个线程获取一个锁并在其间调用
    dequeue()
    ——在第一个线程调用
    notify()
    并完成其
    synchornized
    块之后,但在第二个线程实际从其
    wait()唤醒之前。这是可能的,因为
    synchronized
    /
    wait()
    /
    notify()
    不能保证公平性
因此,应始终在循环内使用
wait()

while (_queue.isEmpty())
    _queue.wait();

这可能至少有两个原因:

  • 贾斯汀·沃(Justin Waugh)指出的虚假唤醒
  • 另一个线程获取一个锁并在其间调用
    dequeue()
    ——在第一个线程调用
    notify()
    并完成其
    synchornized
    块之后,但在第二个线程实际从其
    wait()唤醒之前。这是可能的,因为
    synchronized
    /
    wait()
    /
    notify()
    不能保证公平性
因此,应始终在循环内使用
wait()

while (_queue.isEmpty())
    _queue.wait();

你确定你没有使用空引擎吗?如果(engine!=null)那么{u queue.enqueue(engine);\u queue.notify()}请尝试在“work done”上插入此检查。是的,实际上,被注释的那一行以前是实际的一行,我可以检查队列是否为空。可能读者和作者模式可以解决您的问题:@vtorola-您能提供完整的代码吗,理解目的的需要。您确定您没有使用空引擎吗?如果(engine!=null)那么{u queue.enqueue(engine);\u queue.notify()}请尝试在“work done”上插入此检查。是的,实际上,被注释的那一行以前是实际的一行,我可以检查队列是否为空。可能读者和作者模式可以解决您的问题:@vtorola-您能提供完整的代码吗,理解目的的需要“虚假的觉醒”?好极了我将把它放在一个线程中,启动一个有很多线程的测试,看看会发生什么。万分感谢,“虚假的觉醒”?好极了我将把它放在一个线程中,启动一个有很多线程的测试,看看会发生什么。非常感谢。我刚做了个循环。我无法使用BlockinQueue,因为它在我的环境中不存在。该环境是SAP的一个旧JavaIDE,它没有通用的或任何新的,我认为是Java1!愿原力与你同在;-)我只是做了个循环。我无法使用BlockinQueue,因为它在我的环境中不存在。该环境是SAP的一个旧JavaIDE,它没有通用的或任何新的,我认为是Java1!愿原力与你同在;-)所有线程逻辑都包含在该方法中,队列仅在该方法中使用。所以这可能是第一个选择。我现在正在做一个测试。谢谢。@vtortola:但方法被许多线程调用,对吗?因此,新的调用可能会在两个方法之间发生。所有线程逻辑都包含在该方法中,并且队列仅在该方法中使用。所以这可能是第一个选择。我现在正在做一个测试。谢谢。@vtortola:但方法被许多线程调用,对吗?因此,新的呼叫可能会在两者之间发生。