【问题标题】:Synchronization required on an object which should be singleton by convention按照惯例应该是单例的对象需要同步
【发布时间】:2013-09-11 18:09:36
【问题描述】:

我希望我的类只有一个实例,Format1 应该通过类 Engine 返回:

 public final class Engine {

     private static Format format;

     public Engine(final Param1 param1, final Param2 param2) {
         Engine.format = new FormatV1(param1);   // FormatV1 implements Format
     }

     static Format getFormat(int condition) {
         switch(condition) {
            case 1 : return format;
         }
     }
 }

这是否确保通过 getFormat 只返回一个正确的 Format 实例?

另外,调用 getFormat() 的客户端需要在格式对象上执行方法(它绝对没有状态),但将一个 ByteBuffer 传递给该方法(这个 ByteBuffer 可能会被修改):

 class Client 
 {
     public static void main(String[] args) {

          Format obj = Engine.getFormat(1); // some param
          ByteBuffer buffer;                // read data from disk

          synchronized (obj) {

                 long[] result = obj.method(buffer);

                 if (result == null) {
                      // do something
                 }
          }
     }
 }

这里/这样的同步构造是否确保可序列化?

P.S:我对 Java 很陌生,据我所知,我也可以使方法同步,但我认为检查(结果 == null)也应该包含在关键部分中,所以我决定使用而是同步(obj)构造。如果这是一个愚蠢的问题,请原谅我,但我想确认我的怀疑。

【问题讨论】:

  • 实际上你的方法getFormat是基于一个条件的,所以它不会返回一个单例,除非你总是使用相同的参数(在这种情况下是1
  • 单例类不应有公共构造函数。
  • 我理解并且我将始终发送相同的参数。另外,我知道这不完全是单例。但我想要的是每次 BTSEngine 收到请求时都应该返回相同的对象。

标签: java static synchronization synchronized synchronized-block


【解决方案1】:

目前,您正在 Engine 构造函数中创建 Format 实例,这很可能不是您想要的(您当前的示例会抛出 NullPointerException。

其次,您有 2 个同步问题。首先是格式实例的正确发布。你目前不这样做。您应该使用类初始化(在类创建时实例化格式实例)或使格式成员 volatile 以正确发布格式实例。

其次,如果您的格式实例具有可变状态,那么您应该使 FormatV1 方法本身同步。在使用对象之前让调用者在对象上同步是一个非常糟糕的设计。

【讨论】:

  • 如果我使方法同步..测试条件呢..也需要在某个同步块内..如何实现?
  • 我不明白,“让调用者在使用对象之前对其进行同步”..这不是 synchronized(object) 的主要作用吗?
  • @user1071840 - 你所做的被称为“客户端锁定”,它颠覆了对象封装(例如,FormatV1 impl 可以使用 besides 标准同步来处理线程-安全)。为什么需要测试条件在同步块内?
  • oh..yeah..no 2 个线程可以进入同步方法并看到不一致的结果..是的,将使用同步方法。
【解决方案2】:

您创建了 Engine 类的构造函数来初始化静态变量,而是创建一个静态初始化器,在该方法上使用同步

public static synchronized void initFormat(....) {
   if (format == null) {
      ... create it
   } else {
   .... your chocie: throw an exception or do nothing 
   }
}

【讨论】:

  • 没有可用于静态初始化的参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多