Вызов синхронизированного метода в Java игнорирует флаг инициализации (пружина) - PullRequest
1 голос
/ 18 июня 2020

Извините за плохое название, но объяснение будет очень простым.

У меня есть в Service on Spring этот метод:

private static boolean initialized = false;

@PostConstruct
public void onPostConstruct() {
   synchronized (MyClass.class) {
        if (!initialized) {
            // do some init 
            startThread();
            initialized = true
        }
   }
}

С точки зрения JavaSE, я на 100% уверен, что вызовом не может быть более одного потока, запущенного startThread (). Это как-то связано с загрузкой классов в Spring, потому что существует более одного потока. Я вижу это в логах.

Я не могу воспроизвести ошибку на моем компьютере, только на сервере, и у меня нет доступа, поэтому я спрашиваю здесь. Если кто-то может дать мне немного света! спасибо

Ответы [ 3 ]

2 голосов
/ 19 июня 2020

Ваш код определенно является потокобезопасным . Множественные вызовы startThread () будут возможны только в том случае, если ваш класс загружен больше чем один разными ClassLoaders.

Я не эксперт Spring, но согласно ответам этот вопрос можно указать ClassLoader для каждого ApplicationContext. Если ваш класс должен использоваться в нескольких ApplicationContexts с разными экземплярами ClassLoader, возможно, существуют два объекта класса для вашего класса. Поскольку вы синхронизируете с помощью объекта класса, вызовы onPostConstruct () будут взаимоисключающими только для одного экземпляра класса.

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

0 голосов
/ 19 июня 2020

Я думаю, проблема с порядком выполнения между методом startThread () и переназначением инициализированной переменной.

Первое выполнение: метод startThread (), запускает ли поток ??

в то же время инициализировано, переназначено на true;

0 голосов
/ 18 июня 2020

Во время выполнения значение переменной stati c инициализируется классом, но не экземпляром, поэтому, если у вас есть какой-либо момент вашей службы, изменив инициализированное значение на true, тогда оно изменится на true навсегда для всех экземпляров.

для @PostConstruct он будет вызываться при вызове конструктора, а для сервера Spring весь класс будет построен как bean-компонент во время запуска, поэтому этот метод следует вызывать один раз, поэтому перед запуском службы флаг уже изменено на true.

Я предлагаю вам создать другой метод для изменения флага, а не в пост-конструкции.

...