【问题标题】:Do I need to implement synchronized on writing data to a same file by using BufferedWriter and FileWriter?我是否需要使用 BufferedWriter 和 FileWriter 实现同步将数据写入同一个文件?
【发布时间】:2011-09-29 04:18:26
【问题描述】:

我正在开发 Webmethods 集成服务器。内部有一个 java 服务,它采用静态 java 方法的形式,用于使用 BufferedWriter 和 FileWriter 将数据写入日志文件 (server.log)。静态方法代码是这样的:

public static void writeLogFile(String message) throws ServiceException{
    try {
        BufferedWriter bw = new BufferedWriter(new FileWriter("./logs/server.log", true));
        bw.write(message);
        bw.newLine();
        bw.close();
    } catch (Exception e) {
        throw new ServiceException(e.getMessage());
    }
}

注意:
- 出于示例目的,代码已被简化。
- 我无法更改 writeLogFile 方法声明和属性。这意味着,它将永远是:public static void writeLogFile。禁止此类修改:public synchronized void writeLogFile。

writeLogFile 方法有可能被不同的实例调用,所以我需要确保没有两个或多个实例同时访问同一个资源(server.log)。这意味着,如果有两个实例尝试访问 server.log,其中一个实例必须等待另一个实例完成将数据写入 server.log。

问题是: 我应该更改上面的代码吗?如果是这样,我需要做什么样的修改?我应该在 java 静态方法中实现“同步”吗?

@EJP:
那么,下面哪一个是实现同步的最佳代码?

1)

        FileWriter fw = new FileWriter("./logs/server.log", true);
        synchronized (fw) {
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(message);
            bw.newLine();
            bw.close();
        }

2)

        BufferedWriter bw = new BufferedWriter(new FileWriter("./logs/server.log", true));
        synchronized(bw) {
            bw.write(message);
            bw.newLine();
            bw.close();
        }

3)

        synchronized(util.class) {  //yes, the class name is started with lowercase
            BufferedWriter bw = new BufferedWriter(new FileWriter("./logs/server.log", true));
            bw.write(message);
            bw.newLine();
            bw.close();
        }

4) 其他意见?

谢谢。

【问题讨论】:

    标签: java static synchronized filewriter bufferedwriter


    【解决方案1】:

    只需使方法同步即可。出于二进制兼容性目的,它不会影响其方法签名。

    【讨论】:

    • 我不能这样做,因为我也不能更改方法声明。这是来自 webmethods 的固定规则,它始终是:public static void xxx
    • @suud: synchronized 不需要声明。您只能将其放入定义中。
    • 所以在里面的代码周围放了一个同步的(XXX.class)块。但就我个人而言,我会尽量让作者保持开放。
    • @EJP:请看原帖,我在那边评论了。
    • @suud 我已经回答了所有这些问题。我告诉过你要在类文字上进行同步,而且,正如我告诉 swanliu 的那样,该方法在每次调用时都会创建两个 Writer 的实例,因此在这些上进行同步是徒劳的。
    【解决方案2】:

    我还有一个建议。我想同步可以被视为一个方面,并且可以使用一些 AOP 框架来实现。这符合您不更改代码的要求。但我不是 100% 确定这一点,posted a question 也一样。请监控它的反应。

    【讨论】:

      【解决方案3】:

      没有。 BufferedWriter和FileWriter的基类是java.io.Writer,

      每个写操作都有自己的锁

      Object java.io.Writer.lock
      
      The object used to synchronize operations on this stream. 
      

      尝试将 BufferedWriter bw 设为静态并通过静态方法引用它,因此所有写入都是通过相同的 Writer 对象写入文件

      顺便说一句,我猜你正在发明另一个日志库......也许你可以使用 log4j 或任何类型的日志库来代替

      【讨论】:

      • 没有。那是一个实例成员。该方法的每个调用者都将获得自己的 FileWriter 和 BufferedWriter 实例。
      • 我不使用 log4j,因为 log4j 不支持这种场景:编写输出日志文件名具有模式的 appender 日志文件:moduleName_currentDate.log(currentDate 的模式是 yyyyMMdd) .
      • log4j 支持在运行时创建 FileAppender。检查FileAppender的参数化构造函数logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/…
      • 我误解了这个问题吗?或者您可以将 BufferedWriter bw 设为静态并通过静态方法对其进行引用,因此所有写入都是通过相同的写入器对象写入文件
      • 您可以完全重写代码,我愿意,但您对 OP 代码的回答不正确。您还忽略了缓冲的影响,相反,他正在分别调用 write() 和 newline(),这引入了一个计时窗口。
      猜你喜欢
      • 1970-01-01
      • 2018-08-05
      • 2016-07-29
      • 1970-01-01
      • 2017-06-29
      • 1970-01-01
      • 1970-01-01
      • 2012-03-24
      • 2014-09-01
      相关资源
      最近更新 更多