Объединение объектов с .wait и .notify - PullRequest
0 голосов
/ 11 апреля 2011

Я пытаюсь создать класс в Java, который объединяет объекты.Класс начинает создавать минимальное количество требуемых объектов, когда запросы начинают срабатывать, каждый поток проверяет, есть ли доступный объект, может ли он создать его, потому что максимум еще не достигнут, или если в противном случае он должен ждатьget one.

Идея состоит в том, что потоки должны синхронизироваться, чтобы получить / создать движок, но они могут обрабатываться параллельно (метод 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());

Но в основном это означает, что поток теряет свой ход, и это может означать тайм-аутпозже.

Ответы [ 3 ]

3 голосов
/ 11 апреля 2011

Все вызовы на .wait() должны быть заключены в цикл while. Звонки на номер wait() могут просто случайно проснуться.

Согласно документации : "Как и в версии с одним аргументом, возможны прерывания и ложные пробуждения, и этот метод всегда должен использоваться в цикле:"

1 голос
/ 11 апреля 2011

Это возможно как минимум по двум причинам:

  • Ложные пробуждения, как отметил Джастин Во *
  • Другой поток получает блокировку и вызывает dequeue() между - после того, как первый поток вызвал notify() и завершил свой блок synchornized, но до того, как второй поток фактически проснулся от wait(). Это возможно, потому что synchronized / wait() / notify() не гарантирует справедливость .

Поэтому wait() всегда должен использоваться внутри цикла:

while (_queue.isEmpty())
    _queue.wait();
1 голос
/ 11 апреля 2011

С вашим решением, не каждый ли поток вводит бесконечное ожидание ()?

Обычная идиома выглядит примерно так:

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

С другой стороны, поскольку вы 'Вы уже используете Очередь, почему бы не сделать ее java.util.concurrent.BlockingQueue и бесплатно получить решение для параллелизма?

...