-1

我的应用程序中有一个进程,它通过 Servlet 将文档上传到我的服务器并等待完成,然后服务器使用 2 个线程处理文件,并保持Status运行时的状态。

这是Status该类的外观:

class Status implements Serializable {
    private Integer read;
    private Integer validated = 0;
    private Integer processed = 0;
    private Integer failed = 0;

    public Status (int read) {
        this.read = read;
    }

    /*
     *  Getter methods go here.
     *  No Setter methods.
     */

    public void incrementValidated() {
      synchronized(validated) { validated++; }
    }

    public void incrementProcessed() {
      synchronized(processed) { processed++; }
    }

    public void incrementFailed() {
      synchronized(failed) { failed++; }
    }
}

现在,服务器以这种方式处理文件:

  • 线程根据 DB 值验证读取的行,将正常的行放入队列中。
  • 一个线程一直等待,直到队列中有一批项目,然后它持久化这批 X 项目。

Status项目正常 ( incrementValidated)、项目持久 ( incrementProcessed) 和项目无效 ( incrementFailed) 时更新。Status存储在 a中,其中ConcurrentHashMap<String, Status>key 是用户的 sessionID(因为这个过程可以处理多个请求)。

在进程运行时,客户端也通过 Servlet 轮询服务器,它所做的只是return statusMap.get(sessionId);直到进程完成。

我的问题出现在运行时间过长的文件上,例如 5 分钟。当它运行并轮询服务器以获取状态时,有时所有值都设置回 0,唯一保持不变的值是read属性。
我不确定这怎么可能,因为该对象没有设置器,所以我只能想象该对象正在使用构造函数上的相同值重新实例化,因此保持相同的值。

这甚至可能吗?还是我错过了什么?
(发生这种情况时,地址似乎发生了变化)

4

2 回答 2

4

您的同步已损坏。当你validated++;创建一个新对象时(记住它Integer是不可变的)。所以事实上,根本没有同步。

要解决此问题,请制作原始类型的字段int(如评论中所建议的那样)并使三个方法同步。

int validated;

...

public synchronized void incrementValidated() {
  validated++;
}
于 2013-08-27T14:35:02.480 回答
1

您的同步无效。每次你都创建一个新对象++,因此同步发生在不同的对象上。

使用带有专用Object锁或AtomicIntegers 的简单类型。

此外:您确定不需要使用同一个锁同步所有整数变量吗?在这种情况下,您可以通过将方法标记为 来同步Status自身synchronized

于 2013-08-27T14:43:57.457 回答