使用 .wait 和 .notify 进行对象池

发布于 2024-10-31 17:25:42 字数 1513 浏览 4 评论 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());

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

I'm trying to create a class in java that pool objects. The class starts creating the minimum amount of objects required, when the requests start to kick in, every thread checks if there a object available, if it can create it because the maximum has not been reached yet, or if otherwise it has to wait to get one.

The idea is the threads needs to synchronize to get/create an engine, but they can process in parallel (ProcessWithEngine method). The processing could take a couple of minutes, and apparently it's working as I want.

The problem is, that sometimes when .notify() has been called and a thread is released from the .wait(), the queue has 0 items, and that should be impossible because just before .notify(), an item is added.

What could be the problem?

The code is like this:

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();
    }
}

I've fixed it doing this:

            do
            {
                _queue.wait();

            }
            while(_queue.isEmpty());

But basically this means that a thread is losing its turn, and it could mean a timeout later on.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

最佳男配角 2024-11-07 17:25:42

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

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

All calls to .wait() have to be enclosed in a while loop. Calls to wait() can just randomly wake up.

Per the documentation: "As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:"

柳若烟 2024-11-07 17:25:42

使用您的解决方案,不是每个线程都进入无限的 wait() 吗?

正常的习惯用法是这样的:

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

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

With you solution, doesn't every thread enter an endless wait()?

The normal idiom is something like this:

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

On the other hand, since you're already using a Queue, why not make it a java.util.concurrent.BlockingQueue and get a concurrency solution for free?

星光不落少年眉 2024-11-07 17:25:42

至少有两个原因可能导致这种情况:

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

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

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

It's possible for at least two reasons:

  • Spurious wakeups, as noted by Justin Waugh
  • Another thread acquires a lock and calls dequeue() in between - after the first thread called notify() and finished its synchornized block, but before the second thread actually woke up from its wait(). It's possible because synchronized/wait()/notify() doesn't guarantee fairness.

Therefore wait() should be always used inside a loop:

while (_queue.isEmpty())
    _queue.wait();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文