runnable对象中的此方法是否需要同步?

时间:2012-05-12 23:18:31

标签: java thread-safety synchronized

以下方法属于实现Runnable的对象A.它是通过对象A中的其他方法和run方法中的代码异步调用的(因此,它从其他线程调用,周期为5秒)。

我最终会遇到文件创建异常吗?

如果我使方法同步...总是通过对象A获取锁定? 其中一个调用者处于 run()方法的事实让我困惑:S

感谢您的投入。

private void saveMap(ConcurrentMap<String, String> map) {
    ObjectOutputStream obj = null;
    try {
        obj = new ObjectOutputStream(new FileOutputStream("map.txt"));
        obj.writeObject(map);

    } catch (IOException ex) {
        Logger.getLogger(MessagesFileManager.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
        try {
            obj.close();
        } catch (IOException ex) {
            Logger.getLogger(MessagesFileManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    notifyActionListeners();
}

2 个答案:

答案 0 :(得分:6)

同步实例方法使用this对象作为锁,并防止从不同线程同时执行所有同步实例方法(甚至其他方法)。

要回答有关同步要求的问题,答案基本上是,因为您有多个线程访问相同的方法,因此输出可能会发生冲突。

作为设计评论,我会制作您的saveMap方法static,因为它不会访问任何字段(它是无状态的),而且更强烈地表明对文件的输出是 依赖于实例,因此文件输出可能会与其他实例发生冲突更为明显。

编辑:

以下是我建议的代码:

private static synchronized void saveMap(Map<String, String> map) {
    ...
}

仅供参考,static synchronized方法使用类对象(即MyClass.class),它是一个单例,作为锁对象。

答案 1 :(得分:0)

  

它是通过对象A中的其他方法和run方法中的代码异步调用的(因此,它是从其他线程调用的,周期为5秒)。

鉴于从多个线程调用saveMap,没有同步,您无法保证两个线程不会同时尝试写入同一个文件。这将导致文件格式错误。

最简单的解决方案是使方法同步。

private synchronized void saveMap(ConcurrentMap<String, String> map) { ... }

如果地图足够大,可能会导致程序无响应。另一种选择是写入一个临时文件(每次调用一个新文件),然后通过重命名和删除在map.txt上交换新文件时使用同步。

private void saveMap(ConcurrentMap<String, String> map) {
    File file = ... original code to write to a temporary file ...
    if (file != null) {
        synchronized(this) {
            ... move file over map.txt ...
        }
        notifyActionListeners();
    }
}

请记住,交换两个文件不是原子操作。来自同一程序的任何外部程序或线程可能会捕获map.txt不存在的短时间。我无法在Java中找到原子文件交换方法,但也许会进行一些搜索。