Как синхронизировать статический метод в Java - PullRequest
8 голосов
/ 02 июня 2010

Я задал этот вопрос при реализации одноэлементного паттерна в 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
    }
}

Поскольку я не совсем уверен в поведении статического синхронизированного метода, я получил предложение от Google - не иметь (или как можно меньше) нескольких статических синхронизированных методов в одном классе. Я предполагаю, что при реализации статического синхронизированного метода используется блокировка, принадлежащая объекту Class, так что несколько статических синхронизированных методов могут ухудшить производительность системы.

Я прав? или JVM использует другой механизм для реализации статического синхронизированного метода? Что лучше, если мне нужно реализовать несколько статических синхронизированных методов в классе?

Спасибо всем!

С уважением!

Ответы [ 5 ]

7 голосов
/ 02 июня 2010

Лучший подход (который вносит как можно меньше изменений в ваш код) заключается в следующем:

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 - плохая идея» (например, эта ), я думаю, что то же самое актуально для синхронизации в классе.

3 голосов
/ 02 июня 2010

Существует несколько способов создания синглтона.

Один из рекомендуемых способов - использовать enum (гарантированно создать только один экземпляр):

public enum ConnectionFactory {

  INSTANCE;

}

Или вы можете создать его статически при загрузке класса:

public class ConnectionFactory {

  private static ConnectionFactory INSTANCE = new ConnectionFactory();

  private ConnectionFactory() {}

  public static ConnectionFactory getInstance() {
    return INSTANCE;
  }    

}

Если вам нужно лениво загрузить его, вы можете использовать эту идиому (а не дважды проверенный анти-шаблон блокировки )

public class ConnectionFactory {

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

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

}
2 голосов
/ 02 июня 2010

Статические синхронизированные методы используют блокировку класса. В случае вашего примера это будет доступ к блокировке объекта класса ConnectionFactory. Лучшая практика - не держаться за замки дольше, чем нужно. Наличие нескольких синхронизированных методов само по себе не является проблемой.

2 голосов
/ 02 июня 2010

Да, статические методы синхронизируются на своем объекте класса. Я не буду беспокоиться о производительности здесь, так как, вероятно, это не будет вашей горячей точкой производительности. Делайте это просто, оптимизируйте, когда и где вам нужно.

0 голосов
/ 01 июля 2010

Effective Java рекомендует использовать Enums для создания синглтона. Итак, ваш код будет выглядеть примерно так:

public enum ConnectionFactory{
INSTANCE;

// Other factory methods go here.

}

}

...