Я придумываю этот вопрос при реализации шаблона "одиночка" в 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 - не имеют (или максимально меньше) нескольких статических синхронизированных методов в том же классе. Я предполагаю при реализации статического синхронизированного метода, блокировка принадлежит Объекту класса, используется так, чтобы несколько статических синхронизированных методов могли ухудшить производительность системы.
Я прав? или JVM использует другой механизм для реализации статического синхронизированного метода? Какова лучшая практика, если я должен реализовать несколько статических синхронизированных методов в классе?
Спасибо всем!
С уважением!
Лучший подход (который вносит как можно меньше изменений в ваш код) - это сделать так:
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) {
...
}
}
}
Есть много дискуссий о том, «почему синхронизация на это
это плохая идея »(например, этот ), я думаю, что то же самое актуально и для синхронизации в классе.
Есть несколько способов создать синглтон.
Один из рекомендуемых способов - использовать перечисление (гарантированно создать только один экземпляр):
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;
}
}
Да, статические методы синхронизируются по своему объекту класса. Я бы не стал беспокоиться о производительности здесь, так как, вероятно, это не будет вашей горячей точкой производительности. Делайте это просто, оптимизируйте, когда и где вам нужно.
Статические синхронизированные методы используют блокировку класса. В случае вашего примера это будет доступ к блокировке объекта класса ConnectionFactory. Лучшая практика - не удерживать замки дольше, чем необходимо. Наличие нескольких синхронизированных методов само по себе не является проблемой.
Эффективная Java рекомендует использовать перечисления для создания синглтонов. Итак, ваш код будет выглядеть примерно так:
public enum ConnectionFactory{
INSTANCE;
// Other factory methods go here.
}
}