Потоки Java совместно используют статическую переменную

Существует поток, который отслеживает новые электронные письма, пока статическая переменная tracking истинна. Это выглядит так:

Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
        try  {
            tracking = true;
            while(tracking){
                //check emails
             }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

Я реализовал функцию остановки отслеживания электронных писем, которая в основном устанавливает для tracking значение false.

Отслеживание - это просто private static boolean, который я использую только внутри класса, который выполняет эти задачи.

Может ли такой подход привести меня к какой-либо проблеме?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
506
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Если есть несколько потоков, которые читают и записывают в одну и ту же переменную, вам необходимо использовать синхронизацию (например, AtomicBoolean). В этом конкретном случае достаточно объявить tracking как volatile, чтобы новое значение, установленное для этой переменной в одном потоке, было правильно видно в другом потоке:

private static volatile boolean tracking;

Can this approach lead me to any problem?

Да, оно может.

Вы столкнулись с проблемой «видимости». На самом высоком уровне «видимость» - это способность вашего потока видеть изменения, выполняемые другими потоками. Если вы хотите добиться наглядности, то, согласно спецификации Java, вам необходимо установить связь «происходит до» между считыванием значения и записью значения. Без такой связи нет гарантии, что любая запись в переменную tracking будет видна любым другим потоком, кроме того, который выполнил запись.

В вашем случае на ум приходят две возможности установить отношения «произошло до»:

  1. Вы делаете свой логический volatile при его объявлении (никаких дальнейших изменений в вашей программе не требуется)
  2. Вы преобразуете свое логическое значение в AtomicBoolean (затем вы можете объявить его final и либо использовать tracking.set(false), чтобы отключить отслеживание, либо tracking.get(), чтобы проверить, следует ли еще отслеживать).

Для ясности: не нужно выполнять оба изменения, это одно или другое.

Другие возможности включают в себя: защиту чтения и записи с помощью java.util.Lock, но это перебор.

Вы можете прочитать больше здесь: Как понять, что происходит, прежде чем последовать

Если это поток Только, использующий tracking, и вы просто используете его как способ завершить этот единственный поток, тогда с вами, вероятно, все будет в порядке, хотя это все еще сомнительно. Когда вы устанавливаете для tracking значение false, он может повторяться еще несколько раз, но в конечном итоге он будет читать false (если где-то не будет возвращено значение true, как описано ниже), и он завершится.

Но если есть несколько потоков, которые используют tracking, это определенно может быть проблемой для вас, даже если вы использовали volatile или AtomicBoolean.

Если вы установили tracking на false, но сразу после этого другой из ваших Runnable начинает работать и устанавливает для tracking значение true,

 public void run() {
    try  {
        tracking = true; // <-- sets tracking back to true
        while(tracking){
            //check emails
        }

тогда потоки, которые вы пытались завершить, не прекратятся, поскольку tracking снова верен.

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

Согласны с тем, что без дополнительных гарантий относительно того, когда и как запускаются потоки и сбрасывается переменная отслеживания, вы можете столкнуться с этой проблемой «поверх» / независимо от «проблем с видимостью».

GPI 29.10.2018 15:34

Другие вопросы по теме