我的应用程序中有一个进程,它通过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++; }
}
}
现在,服务器以这种方式处理文件:
当项目正常(Status
),项目持久化(incrementValidated
)以及项目无效时incrementProcessed
),incrementFailed
会更新。
Status
存储在ConcurrentHashMap<String, Status>
中,其中密钥是用户的sessionID(因为此进程可以处理多个请求)。
当进程正在运行时,客户端也通过Servlet轮询服务器,所有操作都是return statusMap.get(sessionId);
,直到进程完成。
我的问题来自运行时间过长的文件,例如5分钟。当它正在运行并轮询服务器以获取状态时,有时所有值都将设置回0,唯一保持不变的值是read
属性。
我不确定这是怎么可能的,因为对象没有setter,所以我能想象的是对象在构造函数上使用相同的值进行重新实例化,因此保持相同的价值。
这甚至可能吗?还是我错过了什么? (当发生这种情况时,地址会发生变化)
答案 0 :(得分:4)
您的同步已中断。当您执行validated++;
时,您将创建一个新对象(请记住Integer
是不可变的)。事实上,根本没有同步。
要解决此问题,请创建基本类型int
的字段(如注释中所示)并使这三种方法同步。
int validated;
...
public synchronized void incrementValidated() {
validated++;
}
答案 1 :(得分:1)
您的同步无效。每次执行++
时都会创建一个新对象,因此会在不同对象上进行同步。
使用具有专用Object
锁定或AtomicInteger
s。
此外:您确定不需要使用相同的锁同步所有整数变量吗?在这种情况下,您可以通过将方法标记为Status
来同步synchronized
本身。