【问题标题】:How to synchronize static method in java如何在java中同步静态方法
【发布时间】:2011-02-26 19:57:49
【问题描述】:

我在 Java 中实现单例模式时提出了这个问题。尽管下面列出的示例不是我的真实代码,但与原始代码非常相似。

public class ConnectionFactory{
    private static ConnectionFactory instance;

    public static synchronized ConnectionFactory getInstance(){
        if( instance == null ){
            instance = new ConnectionFactory();
        }

        return instance;
    }

    private ConnectionFactory(){
        // private constructor implementation
    }
}

因为我不太确定静态同步方法的行为,所以我从谷歌得到了一些建议——在同一个类中不要(或尽可能少)多个静态同步方法。我猜在实现静态同步方法时,使用了属于 Class 对象的锁,这样多个静态同步方法可能会降低系统性能。

我说的对吗?还是JVM使用其他机制来实现静态同步方法?如果我必须在一个类中实现多个静态同步方法,最佳做法是什么?

谢谢大家!

亲切的问候!

【问题讨论】:

  • 您的真实代码是否也与延迟初始化有关?因为这通常会浪费代码和开发人员的时间;在声明中初始化该字段在 99% 的情况下都是正确的,并且不需要同步。

标签: java multithreading concurrency static synchronized


【解决方案1】:

最好的方法(尽可能少地更改代码)是这样做:

public class ConnectionFactory{
    private static ConnectionFactory instance = new ConnectionFactory();

    public static ConnectionFactory getInstance(){
        return instance;
    }

    private ConnectionFactory(){
    }
}

如您所见,getInstance 方法现在没有真正需要,因此您可以将代码简化为:

public class ConnectionFactory{
    public static final ConnectionFactory INSTANCE = new ConnectionFactory();

    private ConnectionFactory(){
    }
}

关于同步的UPD:最好的方法是在外部类不可见的锁上同步,即:

public class ConnectionFactory{
    private static final Object lock = new Object();

    public static void doSmth() {
        synchronized (lock) {

           ...
        }
    }

    public static void doSmthElse() {
        synchronized (lock) {

           ...
        }
    }
}

关于“为什么在this 上同步是个坏主意”有很多讨论(比如this one),我认为在课堂上同步也是如此。

【讨论】:

  • 如果唯一的构造函数抛出异常,它将如何创建instance
  • @unbeli:这是我的错,已更正。但是,如果您甚至不需要实例,如果是正确的解决方案。
  • @unbeli:通过使用私有静态工厂方法或静态初始化程序块。不幸的是,所有关于 Java 内存模型和双重检查锁定的讨论已经用数百个代码示例污染了 Internet,现在这些示例给新手的印象是,在 getInstance() 方法中延迟初始化单例实际上是一个好主意,甚至是常态。
  • 你改正的方式没问题,只是它不是懒惰的,所以它并不能完全解决OP问题
  • @Scobal:阅读链接讨论。简而言之:如果另一个类中的其他人将 synchronized (ConnectionFactory.class){} 放在同步上,则可能会在 ConnectionFactory.class 上造成死锁。
【解决方案2】:

有几种方法可以创建单例。

一种推荐的方法是使用枚举(保证只创建一个实例):

public enum ConnectionFactory {

  INSTANCE;

}

或者您可以在类加载时静态创建它:

public class ConnectionFactory {

  private static ConnectionFactory INSTANCE = new ConnectionFactory();

  private ConnectionFactory() {}

  public static ConnectionFactory getInstance() {
    return INSTANCE;
  }    

}

如果你需要延迟加载,你可以使用这个成语(而不是double checked locking anti-pattern

public class ConnectionFactory {

  private static class ConnectionFactoryHolder {
    private static ConnectionFactory INSTANCE = new ConnectionFactory();
  }

  public static ConnectionFactory getInstance() {
    return ConnectionFactoryHolder.INSTANCE;
  }

}

【讨论】:

    【解决方案3】:

    是的,静态方法在它们的类对象上是同步的。我不会担心这里的性能,因为这可能不是您的性能热点。做简单的事,优化您需要的时间和地点。

    【讨论】:

      【解决方案4】:

      静态同步方法使用类上的锁。在您的示例中,它将访问 ConnectionFactory 类对象上的锁。最佳做法是不要持有超过你必须的时间。是否有多个同步方法本身不是问题。

      【讨论】:

        【解决方案5】:

        Effective Java 推荐使用 Enums 来创建单例。所以你的代码看起来像这样:

        public enum ConnectionFactory{
        INSTANCE;
        
        // Other factory methods go here.
        
        }
        

        }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-25
          相关资源
          最近更新 更多