Java对象可以自行重新实现吗?

时间:2013-08-27 14:23:47

标签: java multithreading servlets

我的应用程序中有一个进程,它通过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存储在ConcurrentHashMap<String, Status>中,其中密钥是用户的sessionID(因为此进程可以处理多个请求)。

当进程正在运行时,客户端也通过Servlet轮询服务器,所有操作都是return statusMap.get(sessionId);,直到进程完成。

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

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

2 个答案:

答案 0 :(得分:4)

您的同步已中断。当您执行validated++;时,您将创建一个新对象(请记住Integer是不可变的)。事实上,根本没有同步。

要解决此问题,请创建基本类型int的字段(如注释中所示)并使这三种方法同步。

int validated;

...

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

答案 1 :(得分:1)

您的同步无效。每次执行++时都会创建一个新对象,因此会在不同对象上进行同步。

使用具有专用Object锁定或AtomicInteger s。

的简单类型

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