-1

Рассмотрим следующий код, реализующий двойную проверку блокировки, используя synchronized ключевое слово в JAVA 8:Преобразовать двойную проверку блокировки с использованием синхронизирована замков в JAVA

private static void redoHeavyInitialisation() { 
    if (needToReinitialise()) { 
     synchronized (MyClass.class) { 
      if (needToReinitialise()) { 
       doHeavyInitialisation(); 
      } 
     } 
    } 
} 

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

Как бы то ни было, во-первых, как вы преобразовываете код выше, чтобы использовать Lock из параллельного пакета JAVA вместо использования синхронизированного ключевого слова?

Только после этого И необязательно прокомментируйте использование блокировки или синхронизированного ключевого слова, которое лучше.

Помните, что этот вопрос не касается синхронизации с синхронизированным сравнением. Ответные попытки, не отвечая на часть преобразования кода, не будут выбраны в качестве принятого ответа.

+0

Возможный дубликат [Синхронизация против Lock] (http://stackoverflow.com/questions/4201713/synchronization-vs-lock) –

+0

@ErwinBolwidt Да, если вы сосредоточены только на сравнении и полностью игнорируете этот вопрос, требуя эквивалентного преобразования кода, что является основным вопросом. Вам не нужно комментировать сравнение, если вы не хотите этого, но ответьте на конвертацию кода, пожалуйста. – user1589188

+0

Вы можете использовать singleton. Одной возможной архитектурой будет создание класса Singleton HeavyInitializer с синхронизированными методами для инициализации и повторной инициализации. – Chocksmith

ответ

1

Преобразование синхронизированных блоков в эквивалентный блок с использованием ReentrantLock довольно круто.

Сначала вы создаете блокировку с тем же или подобным масштабом и временем жизни, что и объект, на котором вы блокировали. Здесь вы запираетесь на MyClass.class, следовательно, статический замок, поэтому вы можете сопоставить это со статическим замком в MyClass, например MyClass.initLock.

Тогда просто сменяют друг:

synchronized (object) { 

с

lock.lock(); 
try { 

и каждой ассоциированной закрывающей скобки с

} finally { 
    lock.unlock(); 
} 

Собираем все вместе у вас есть:

private final static ReentrantLock initLock = new ReentrantLock(); 

private static void redoHeavyInitialisation() { 
    if (needToReinitialise()) { 
     MyClass.initLock.lock(); 
     try { 
      if (needToReinitialise()) { 
       doHeavyInitialisation(); 
      } 
     } finally { 
      MyClass.initLock.unlock(); 
     } 
    } 
} 

Эффективность - это небольшой дневной свет между подходами. Они, по сути, имеют одинаковую семантику и обычно используют аналогичные базовые механизмы. Раньше были различия в производительности - иногда были оптимизированы эффекты, влияющие на то или другое, поэтому на некоторых JVM вы можете найти разницу, но цель двойной блокировки заключается в том, чтобы избежать блокировки в любом случае, так что просто делайте то, что проще всего. Вы получаете блокировку только в течение очень небольшого переходного периода, в то время как метод needToReinitialise() работает, поэтому стоимость блокировки не будет иметь никакого постоянного воздействия.

+0

Спасибо. Почти лучший ответ. Не могли бы вы прокомментировать, почему он должен быть «ReentrantLock», но не используются другие варианты «Lock»? – user1589188

+0

«ReentrantLock» - это единственная прямо реалистичная реализация интерфейса «Lock», который я знаю на Java 8. О каких других реализациях вы говорите? @ user1589188 – BeeOnRope

+0

Извините, что я имел в виду блокировку. Другие, такие как чтение/запись, печать, блокировка. – user1589188

0

Рассмотрим следующий код:

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

public class HeavyInitializer { 
static final Logger logger = LoggerFactory.getLogger(HeavyInitializer.class); 
static HeavyInitializer singleton; 
public static synchronized HeavyInitializer getInstance() { 
    if (singleton==null) { 
     singleton = new HeavyInitializer(); 
    } 
    return singleton; 
} 
boolean initialized; 
private HeavyInitializer() { 
    initialized = false; 
} 

public synchronized void initialize() { 
    if (!initialized) { 
     heavyStuffDoneHere(); 
    } 
} 
public synchronized void reInitilize() { 
    if (needToReinitialise()) { 
     heavyStuffDoneHere(); 
    } 
} 

private void heavyStuffDoneHere() { 
    initialized = true; 
} 

private boolean needToReinitialise() { 
    if (!initialized) 
     return false; 
    boolean ret = false; 
    //Do your check here... and set ret  
    return ret; 
} 

} 

От Oracle's doc:

... затем делает эти методы синхронизированные имеет два эффекта:

  • во-первых, это не возможно для двух вызовы синхронизированных методов на одном объекте для чередования. Когда один поток выполняет синхронизированный метод для объекта, все другие потоки, которые вызывают синхронизированные методы для одного и того же блока объектов (приостанавливают выполнение) до тех пор, пока первый поток не будет выполнен с объектом.

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

Попытка использования блокировки будет пытаться выполнить синхронизированный блок. Не обязательно.

+0

Спасибо за ваши усилия. Я хотел бы дать вам оценку, но то, что у вас там, использует «синхронизированный», как пример в моем вопросе, который вообще не отвечает на мой вопрос. – user1589188

+1

Просто пытаюсь внести вклад и представить альтернативную архитектуру. Мой опыт показывает, что повторное выполнение синхронизации с блокировками или семафорами приведет к сложным ошибкам, которые будут решаться во время выполнения. Я бы использовал синхронизированную архитектуру singleton. – Chocksmith

-1

Singleton Double проверяет блокировку и предотвращает разрыв объекта singleton с использованием сериализации.

package pattern.core.java; импорт java.io.Serializable;

общественного класса Singleton расширяет объект реализует Serializable {

private static final long serialVersionUID = 1L; 
private static Singleton sg; 

private Singleton() { 
} 

public static Singleton getSingletonObj() { 
    if (sg == null) { 
     synchronized (sg) { 
      if (sg == null) { 
       sg = new Singleton(); 
      } 
     } 
    } 
    return sg; 
} 


/* 
* this method ensures that new object will not be created for singleton 
* class using serialization and deserialization 
*/ 
protected Object readResolve() { 
    return sg; 
} 

/* 
* @Override protected Object clone() throws CloneNotSupportedException { 
* throw new CloneNotSupportedException(); } 
*/ 

@Override 
protected Object clone() throws CloneNotSupportedException { 
    return sg; 
} 

}

+1

правильно отформатируйте свой код – Ibo

Смежные вопросы