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

Java 当共享变量可以随时更改时,如何使代码线程安全?,java,multithreading,thread-local,Java,Multithreading,Thread Local,这是一个被问了很多次的问题,我已经仔细检查了以前提出的许多问题,但是没有一个给我答案,所以我想我会把它放在这里 问题是让我的代码在java中线程安全,因为我知道只有一个共享变量,但它可以随时更改。实际上,我觉得我正在优化的代码没有被考虑用于多线程环境,所以我可能必须仔细考虑一下 基本上,我有一个类可以在5个线程之间共享。这个类有一个私有属性“myProperty”,它可以接受5个不同的值(每个线程一个)。问题是,一旦构造函数实例化了该值,该值在线程的剩余生命周期中就不应该再更改了 我非常清楚一些

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

问题是让我的代码在java中线程安全,因为我知道只有一个共享变量,但它可以随时更改。实际上,我觉得我正在优化的代码没有被考虑用于多线程环境,所以我可能必须仔细考虑一下

基本上,我有一个类可以在5个线程之间共享。这个类有一个私有属性“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        
}

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

我不确定是否完全理解这种情况,但如果您希望确保每个线程使用特定于线程的实例作为变量,解决方案是使用类型为
ThreadLocal

的变量。我不能100%确定我是否正确理解了您的问题,但我还是要试一试。如果我错了,请纠正我

“简单”的解决方法是创建一个表(operatorList) 例如(或列表、地图等)将运算符与 它调用线程的ID,这样每个线程只需 使用其在表中的id访问其运算符,但这样做会 让我们更改访问共享变量的所有线程类 还有很多

Java中已经有类似的东西了——类

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

 private static final ThreadLocal<MyObject> operator =
     new ThreadLocal<MyObject>() {
         @Override 
         protected MyObject initialValue() {
             // return thread-local copy of the "MyObject"
     }
 };
专用静态最终线程本地运算符=
新ThreadLocal(){
@凌驾
受保护的MyObject初始值(){
//返回“MyObject”的线程本地副本
}
};

在代码的后面,当特定线程需要获取自己的本地副本时,它所需要做的就是:
operator.get()
。实际上,
ThreadLocal
的实现与您描述的类似-每个线程的
ThreadLocal
值的映射。只有
映射
不是静态的,实际上是绑定到特定线程的。这样,当一个线程死亡时,它会带上它的
ThreadLocal
变量?您想唯一地标识线程吗?那么您是否有(或想要)一个
共享的
实例(在这种情况下,
myProperty
不能接受5个值),或者是5个
共享的
实例(在这种情况下,您是如何将Spring设置为Autowire的?@Elias:我希望每个线程都能看到共享的不同值#operatorAh,您正在寻找的术语是“线程本地”。您猜对了-Spring默认为Singleton作用域(这里有一些有趣的阅读:)。对于这个问题,是的-ThreadLocal是一个不错的选择。不,你完全明白我的问题,我会试试这个,谢谢!!这只有一条注释:自Java8以来,使用lambda更容易创建它,例如:
ThreadLocal operator=ThreadLocal.withInitial(()->“value”)