Использование AtomicInteger и CountDownLatch для генерации одного экземпляра - PullRequest
0 голосов
/ 31 мая 2019

У меня есть класс, который я хочу иметь только один экземпляр.Однако я не хочу, чтобы несколько потоков вызывали getInstance().Поэтому я закодировал это следующим образом

public class SomeService implements Provider<String, Claims>{

    private SomeService(String a, String b, String c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }



    // single instance
    private static SomeService instance = null;

    private String a;
    private static AtomicInteger initialized = new AtomicInteger();
    private static CountDownLatch latch = new CountDownLatch(1);
    private String b;
    private String c;


    public static SomeService getInstance(String a, String b, String c) {
       if ( initialized.incrementAndGet() == 1) {
           instance = new SomeService(a, b, c);
           latch.countDown();
       } else {
           try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } 
       }
       return instance;

    }

    // Other implementation code

    }

Мое намерение (и понимание этого) заключается в следующем:

  1. Когда поток вызывает getInstanceон будет атомарно увеличиваться и проверять, является ли его желаемое значение.

  2. Если нет, он будет ждать, пока другой поток откроет защелку, что означает, что инициализация выполняется.

Было бы полезно, если бы кто-то помог мне исправить мои ошибки.Мне кажется, что я, вероятно, могу просто сделать блок synchronized(someLockObject) {}, но мне было интересно, имеет ли это смысл вообще.

Ответы [ 2 ]

1 голос
/ 31 мая 2019

Мое намерение (а также понимание этого) заключается в том, что:

1) Когда поток вызывает getInstance, он атомарно увеличивается и проверяет, является ли его желаемое значение.

Да.

2) Если нет, он будет ждать, пока другой поток откроет защелку, что означает, что идет инициализация.

Да.

Сдается мне, что я, вероятно, могу просто сделать synchronized(someLockObject) {} блок

Да, и это было бы более типично.

Мне было интересно, еслиэто вообще имеет смысл.

Код будет работать так, как вы, похоже, намереваетесь, если только getInstance() не будет вызываться достаточно раз для initialized, чтобы вернуться к 0. Я был бы склонен коднако вместо этого используйте AtomicBoolean и его метод compareAndSet(), так как это, кажется, лучше моделирует ситуацию (и это не представляет никакого риска для любой ситуации).

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

Но в целом подход кажется плохо продуманным, поскольку поток, который вызывает getInstance() с одним набором аргументов, может получить экземпляр, который был инициализирован с другим набором параметров.Это может быть признаком того, что вместо этого варианта шаблона Singleton вам лучше использовать шаблон «просто используйте один».В частности, обратите внимание, что некоторые люди считают синглтон анти паттерном .

0 голосов
/ 01 июня 2019

Полагаю, дизайн здесь в корне неверный. я считаю, что должен делать

1) Поместите больше слоя абстракции и убедитесь, что используется шаблон строителя.

2) Когда моя служба нуждается в обслуживании, она может использовать свойства инициализации, чтобы определить, какой компоновщик использовать, а затем выполнить эту работу.

3) Если возможно, я также могу комбинировать его с фабрикой.

Не знаю, имеет ли смысл вышесказанное, но это устраняет необходимость в antipattern или "Singleton".

...