Как сделать мой код потокобезопасным, когда моя переменная общего доступа может измениться в любое время? - PullRequest
0 голосов
/ 14 октября 2019

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

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

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

Мне довольно хорошо знакомы некоторые методы, используемые для превращения большей части кода в «thead-safe», включая блокировки, «синхронизированные» ключевые слова, переменные и атомарные типы, но у меня есть ощущение, что они выиграли »t помочь в текущей ситуации, так как они не препятствуют изменению переменной.

Вот код:

// The thread that calls for the class containing the shared variable //

public class myThread implements Runnable {

     @Autowired
     private Shared myProperty;

     //some code
}

// The class containing the shared variable //

public class Shared {

      private String operator;
      private Lock lock = new ReentrantLock();

      public void inititiate(){
           this.lock.lock()
           try{
                 this.operator.initiate() // Gets a different value depending on the calling thread
           } finally {
                 this.lock.unlock();
           }
      } 

      // some code        
}

Как это происходит, приведенный выше код гарантирует, что выиграли только два потокане изменяйте переменную одновременно, но последняя все равно изменится. «Наивный» обходной путь будет состоять в создании таблицы (operatorList), например (например, списка, карты и т. Д.), Связывающей оператор с идентификатором его вызывающего потока, таким образом, каждый поток просто должен будет получить доступ к своему оператору, используя свой идентификаторв таблице, но это заставит нас изменить все классы потоков, которые обращаются к общей переменной, и их много. Любая идея относительно того, как я мог бы хранить различные значения строки оператора исключительным образом для каждого вызывающего потока с минимальными изменениями (без использования магии)?

Ответы [ 2 ]

3 голосов
/ 14 октября 2019

Я не уверен на 100%, что правильно понял ваш вопрос, но я все равно попробую. Поправьте меня, если я ошибаюсь.

"Наивный" обходной путь будет состоять в создании таблицы (operatorList), например (или списка, карты и т. Д.), Связывающей оператор с его вызовомID потока, таким образом, каждый поток должен был бы просто получить доступ к своему оператору, используя свой идентификатор в таблице, но это заставило бы нас изменить все классы потока, которые обращаются к общей переменной, и их много.

В Java уже есть нечто похожее - класс ThreadLocal ?

Вы можете создать локальную для потока копию любого объекта:

 private static final ThreadLocal<MyObject> operator =
     new ThreadLocal<MyObject>() {
         @Override 
         protected MyObject initialValue() {
             // return thread-local copy of the "MyObject"
     }
 };

Позже в вашем коде, когдаконкретный поток должен получить свою собственную локальную копию, все, что ему нужно сделать, это: operator.get(). В действительности реализация ThreadLocal похожа на то, что вы описали - Карта значений ThreadLocal для каждого потока. Только Map не является статичным и фактически привязан к конкретному потоку. Таким образом, когда поток умирает, он берет с собой ThreadLocal переменные.

3 голосов
/ 14 октября 2019

Я не уверен, полностью ли я понимаю ситуацию, но если вы хотите убедиться, что каждый поток использует для переменной экземпляр, специфичный для потока, решение состоит в том, чтобы использовать переменную типа ThreadLocal<T>.

...