我正在开发一个遗留Java 1.4项目,我有一个工厂将csv文件解析器实例化为单例。
但是,在我的csv文件解析器中,我有一个HashSet,它将存储从我的CSV文件的每一行创建的对象。所有这些都将由Web应用程序使用,用户可能会同时上传CSV文件。
现在我的问题是:防止2个用户修改对象列表的最佳方法是什么?
到目前为止,我正在做以下事情:
final class MyParser {
private File csvFile = null;
private Set myObjects = Collections.synchronizedSet(new HashSet);
public synchronized void setFile(File file) {
this.csvFile = file;
}
public void parse()
FileReader fr = null;
try {
fr = new FileReader(csvFile);
synchronized(myObjects) {
myObjects.clear();
while(...) { // foreach line of my CSV, create a "MyObject"
myObjects.add(new MyObject(...));
}
}
} catch (Exception e) {
//...
}
}
}
我应该只将锁保留在myObjects Set上,还是应该将整个parse()方法声明为synchronized?
另外,我应该如何同步 - 两者 - csvFile的设置和解析?我觉得我的实际设计被破坏了,因为线程可以在可能很长的解析过程运行时多次修改csv文件。
我希望我足够清楚,因为我对这些多同步问题感到有些困惑。
谢谢; - )
答案 0 :(得分:3)
我认为此代码中存在多个问题。
如果此类是单例,则此类应该是无状态的,即此类中不应存在任何状态。因此,拥有文件本身的setter是不正确的。将文件对象传递给parse方法,让它处理参数。这应该可以解决您在各种方法中同步的问题
虽然你的myObjects Set是私有的,但我假设你没有将它传递给任何其他调用类。如果你是,总是返回此集的克隆,以避免调用者对原始集进行更改。
如果所有设置更改都在同步块中,则对象上的同步就足够了。
答案 1 :(得分:3)
基本上你假设方法首先需要setFile然后调用解析器。让我们考虑一下, t1(带有setFile XX)和t2(带有setFile YY)同时出现,t2将文件设置为YY。然后t1请求parse()并开始从YY获取记录。没有任何synchronized会为你解决这个问题,唯一的出路就是让parse方法获取File参数或删除单例约束(这样每个线程都有自己的文件对象)。所以使用
public void parse(File file) //and add synchronised if you want.
答案 2 :(得分:2)
为每个解析请求使用单独的MyParser
对象,您不必处理并发(至少不在MyParser
中)。此外,您将能够一次真正为多个用户提供服务,而不是强迫他们等待或删除以前解析作业的结果。
答案 3 :(得分:-1)
单身的东西大多是红鲱鱼。与您正在考虑的并发问题无关。就同步而言,我认为你没问题。尽管myObjects
是静态,因为它是一个单例,但使方法同步也会有效。