当等待Vector对象的线程数大于6时,wait和notifyAll机制无法按预期工作



我的应用程序中有一个要求,其中'N'数量的产品可以与报价关联。屏幕布局将分为两部分。顶部有一个包含报价相关信息的表单,底部用于容纳多个产品。我通过在底部添加iframe来实现此功能。单击按钮(使用javascript)将添加/删除产品。每个Product窗口中显示的内容将由相同的Action(ProductLinesAction.java)、JSP(ProductLines.JSP)和其他相关资源呈现。这里的重点是,每当屏幕上加载新的Product窗口时,就会创建该Action类的多个实例。我在加载窗口时没有问题,因为它只是准备显示表单。当要保存报价时,所有这些产品表单都将被提交,我所包含的逻辑是,1到N-1个动作实例将把表单值放在VO中,VO被添加到Vector对象中并保存在会话中(这样其他动作实例就可以从会话中获取它并添加到它上面)。第N个操作实例旨在将所有这些乘积值集中保存。业务规则验证也在保存之前执行,因此第N个操作实例将可用,错误应显示在每个"产品"窗口中。

为了确保所有其他操作实例也能利用与其窗口对应的错误,我实现了wait and notifyAll机制,当尝试保存6个以上的产品时,就会出现问题。代码如下所示。这段代码适用于小于或等于6的产品(我的意思是最多6个操作实例)。当加载并保存第7个产品时,第7个实例在调试模式下根本不可见或不可跟踪(实例在提交表单时未达到预期方法)。

有人能阐明这里犯下的错误吗?这个错误是造成这个问题的原因。

public String submitProducts()
throws Exception {
String resultValue = "";
/* Algorithm: */
// 1. Read the Vector object from Session.
// 2. Check whether the size of the Vector matches the Total Product windows count.
// 3. If yes, call the Save operation and remove the list from session.
// 4. If not, copy the values from current Action instance to VO.
// 5. Add to List object and place in session.
synchronized (productVOsInVector) {
productVOsInVector = getProductVOVectorFromSession();
if (productVOsInVector == null) {
productVOsInVector = new Vector <ProductVO>();
}
log.info("Window Number is " + activeWindowNumber + ". List size is " + productVOsInVector.size());
if (productVOsInVector.size() == (prodWindowCount - 1)) {
productVOsInVector = mapActionToVO(productVOsInVector);
resultValue = saveOperation(productVOsInVector);
if (resultValue.equalsIgnoreCase(SUCCESS)) {
session.put("OperationStatus", SUCCESS);
}
session.remove("productVOMapData");
}
else {
if (quoteSaveStatus) {
quoteSaveStatus = false;
}
session.put("OperationStatus", "");
productVOsInVector = mapActionToVO(productVOsInVector);
session.put("productVOMapData", productVOsInVector);
}
waitForOperationStatus();
}
System.out.println("Came out of sync block");
System.out.println("Action Instance" + activeWindowNumber + " is resuming.");
// Code to display the Error messages
return resultValue;
}
public void waitForOperationStatus() {
String opStatus = getOperationStatusFromSession();
synchronized (productVOsInVector) {
if (!opStatus.equalsIgnoreCase(SUCCESS)) {
try {
System.out.println("Window # " + activeWindowNumber + " Waiting");
productVOsInVector.wait();                  
}
catch (InterruptedException e) {
e.printStackTrace();
}
opStatus = getOperationStatusFromSession();
}
productVOsInVector.notifyAll();
}
}

以下内容本身就已经是一个严重的问题:

synchronized (productVOsInVector) {
productVOsInVector = getProductVOVectorFromSession();
if (productVOsInVector == null) {
productVOsInVector = new Vector <ProductVO>();
}
...
}

您正在对productVOsInVector引用的对象进行同步,并立即使引用指向另一个对象。因此,下一个线程将在与第一个不同的对象上同步。

然后你正在等待这个物体,并希望有人会通知你。

我没有分析更多,但你有一个严重的设计问题。首先不应该在servlet容器的线程之间进行同步。如果池中只有6个线程,而它们都在等待第7个线程完成,那么就会出现死锁。如果池中有12个线程,而两个客户端同时执行,那么也会出现死锁。即使没有死锁,也会使几个线程不可用,只需等待,希望后续的HTTP请求会通知它们。如果最后一个请求不是出于某种原因(例如,用户杀死了他的浏览器,你有6个线程永远被阻止

因此,我的建议是:不要弄乱线程。找到另一种方式。

最新更新