使用 .wait 和 .notify 进行对象池
我正在尝试在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对
.wait()
的所有调用都必须包含在while
循环中。调用wait()
可以随机唤醒。根据文档 :“与单参数版本一样,中断和虚假唤醒是可能的,并且此方法应始终在循环中使用:”
All calls to
.wait()
have to be enclosed in awhile
loop. Calls towait()
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:"
使用您的解决方案,不是每个线程都进入无限的 wait() 吗?
正常的习惯用法是这样的:
另一方面,既然您已经在使用队列,为什么不将其设为 java.util.concurrent.BlockingQueue 并免费获得并发解决方案呢?
With you solution, doesn't every thread enter an endless wait()?
The normal idiom is something like this:
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?至少有两个原因可能导致这种情况:
dequeue()
- 在第一个线程调用notify()
之后> 并完成其synchronized
块,但在第二个线程实际从其wait()
中唤醒之前。这是可能的,因为synchronized
/wait()
/notify()
不能保证公平性。因此
wait()
应始终在循环内使用:It's possible for at least two reasons:
dequeue()
in between - after the first thread callednotify()
and finished itssynchornized
block, but before the second thread actually woke up from itswait()
. It's possible becausesynchronized
/wait()
/notify()
doesn't guarantee fairness.Therefore
wait()
should be always used inside a loop: