【问题标题】:StringBuffer or synchronized method?StringBuffer 还是同步方法?
【发布时间】:2018-01-27 12:28:00
【问题描述】:

我有以下代码:

public class MyLogger {
   private StringBuilder logger = new StringBuilder();

   public void log(String message, String user) {
      logger.append(message);
      logger.append(user);
   }
}

程序员必须保证单个 MyLogger 对象可以正常工作 多线程系统。 这段代码必须如何更改为线程安全的?

A.同步日志方法

B.将StringBuilder 替换为StringBuffer

请告知最佳方法。

【问题讨论】:

  • 那么这个在logger中累积,有什么意义呢?

标签: java multithreading stringbuilder synchronized stringbuffer


【解决方案1】:

StringBuffer 不足以保证这两个信息总是分组发送:

  logger.append(message);
  logger.append(user);

它只保证append() 不会以并发方式被调用,因此您不会冒险破坏StringBuffer 对象的状态。
您确实可以有两个线程在 log() 调用期间交错并获取这些调用:

线程 1:logger.append(message);

线程 2:logger.append(message);

线程 1:logger.append(user);

线程 2:logger.append(user);

这样更好:

  public synchronized void log(String message, String user) {
      logger.append(message);
      logger.append(user);
   }

您还可以在私有 logger 对象上进行同步。
这样做的好处是不允许类的客户端将其锁定在类之外。

【讨论】:

  • 您可能想提一下,与在方法签名上使用synchronized 相比,在私有对象上进行同步是更好的选择。
  • @Alvin Thompson 很好的建议。我加了。
  • 感谢@davidxxx 的精彩描述。如果我的理解有误,请告诉我:说,线程 1 有机会执行 logger.append(message);所以 T1 对 SB 对象有锁定,并且在方法执行完成后它会释放对 SB 的锁定?所以 T2 可以执行 logger.append(message);因此可能会出现问题?这是你想要描述的吗?
  • 不客气。您很接近,“并且在方法执行完成后,它可能释放锁定”。
  • 好的。因此,当 T1 释放锁并且 T2 可能开始执行时,就会出现问题,即线程 1:logger.append(message);线程 2:logger.append(message);线程 1:logger.append(user);线程 2:logger.append(user);否则,如果 T1 持有锁,那么它可以继续: logger.append(user);并且 T2 不会有机会,所以这将是:线程 1 : logger.append(message);线程 1:logger.append(user);线程 2:logger.append(message);线程 2:logger.append(user);
【解决方案2】:

使用 A,因为如果您选择使用 StringBuffer,您可能会弄乱日志: StringBuffer 可能会发生这种情况(会生成错误的日志):

logger.append(message); < Thread A
logger.append(message); < Thread B
logger.append(user);  < Thread A
logger.append(user); < Thread B

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-04
    • 2011-09-11
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多