包含可变字段的Java 1.4单例

时间:2010-03-16 16:42:38

标签: java concurrency synchronization

我正在开发一个遗留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文件。

我希望我足够清楚,因为我对这些多同步问题感到有些困惑。

谢谢; - )

4 个答案:

答案 0 :(得分:3)

我认为此代码中存在多个问题。

  1. 如果此类是单例,则此类应该是无状态的,即此类中不应存在任何状态。因此,拥有文件本身的setter是不正确的。将文件对象传递给parse方法,让它处理参数。这应该可以解决您在各种方法中同步的问题

  2. 虽然你的myObjects Set是私有的,但我假设你没有将它传递给任何其他调用类。如果你是,总是返回此集的克隆,以避免调用者对原始集进行更改。

  3. 如果所有设置更改都在同步块中,则对象上的同步就足够了。

答案 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是静态,因为它是一个单例,但使方法同步也会有效。