当等待Vector对象的线程大于6时,wait和notifyAll机制无法正常工作

0 java concurrency multithreading thread-safety

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

为了确保所有其他操作实例也可以利用与其窗口相对应的错误,我实现了wait和notifyAll机制,其中当尝试保存超过6个产品时出现问题.代码如下.这段代码适用于小于或等于6的产品(我的意思是最多6个动作实例).加载并保存第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();
    }
}
Run Code Online (Sandbox Code Playgroud)

JB *_*zet 5

以下是一个严重的问题:

synchronized (productVOsInVector) {
    productVOsInVector = getProductVOVectorFromSession();
    if (productVOsInVector == null) {
        productVOsInVector = new Vector <ProductVO>();
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

然后你在等这个对象,并希望有人会通知你.

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

因此我的建议是:不要乱用线程.找另一种方式.