当我的共享变量可以随时更改时,如何使我的代码线程安全?

How to make my code thread-safe when my shared variable can change anytime?

这是一个被问过很多次的问题,我已经仔细检查了以前提出的许多问题,但 none 给了我一个答案元素,所以我想我会把它放在这里。

问题是关于在 java 中使我的代码线程安全,知道只有一个共享变量,但它可以随时更改,实际上我觉得我正在优化的代码没有被考虑过对于多线程环境,所以我可能要考虑一下...

基本上,我有一个 class 可以在 5 个线程之间共享。这个 class 有一个私有的 属性 'myProperty' 可以取 5 个不同的值(每个线程一个)。问题在于,一旦它被构造函数实例化,该值在线程的剩余生命周期内不应再更改。

我非常了解用于转换大部分代码的一些技术 "thead-safe" 包括锁、"synchronized" 关键字、volatile 变量和原子类型,但我感觉这些技术赢了' 在当前情况下提供帮助,因为它们不会阻止修改变量。

这是代码:

// 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        
}

巧了,上面的代码只是保证两个线程不会同时改变变量,而后者还是会改变。 "naive" 解决方法包括创建一个 table (operatorList) 例如(或列表、映射等),将运算符与其调用线程的 ID 相关联,这样每个线程只需要使用其在 table 中的 id 访问其运算符,但这样做会使我们更改所有访问共享变量的线程 classes 并且有很多。关于如何以独占方式为每个调用线程存储不同的运算符字符串值并进行最小更改(不使用魔法)的任何想法?

我不确定我是否完全理解这种情况,但是如果你想确保每个线程都使用线程特定的变量实例,解决方案是使用ThreadLocal<T>类型的变量。

我不能 100% 确定我是否正确理解了你的问题,但无论如何我都会试一试。如果我错了,请纠正我。

A "naive" workaround would consist in creating a table (operatorList) for instance (or a list, a map, etc. ) associating an operator with its calling thread's ID, this way each thread would just have to access its operator using its id in the table but doing this would make us change all the thread classes which access the shared variable and there are many.

Java 中已有类似内容 - ThreadLocal class?

您可以创建任何对象的线程本地副本:

 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 个变量。