Java 不可变对象上的线程安全

Java 不可变对象上的线程安全,java,string,immutability,Java,String,Immutability,我在读java中的不可变对象 有一条语句声明:“不可变对象是线程安全的”。 我需要对上述声明进行更多澄清: 如果我有一个“String”类型的共享资源,它与多个线程共享(比如3个线程) 如果其中一个线程对共享引用进行了更改,它将创建一个新的字符串对象,该对象将仅对该线程对象可用,而其他线程将无法了解其中一个线程所做的更改 这不会导致数据不一致吗 有人能帮我理解吗 提前感谢。不可变类的对象始终是线程安全的。但是,对这样一个对象的引用与此无关。它可能是线程安全的,也可能不是线程安全的,这取决于包含对

我在读java中的不可变对象

有一条语句声明:“不可变对象是线程安全的”。 我需要对上述声明进行更多澄清:

如果我有一个“String”类型的共享资源,它与多个线程共享(比如3个线程) 如果其中一个线程对共享引用进行了更改,它将创建一个新的字符串对象,该对象将仅对该线程对象可用,而其他线程将无法了解其中一个线程所做的更改

这不会导致数据不一致吗

有人能帮我理解吗


提前感谢。

不可变类的对象始终是线程安全的。但是,对这样一个对象的引用与此无关。它可能是线程安全的,也可能不是线程安全的,这取决于包含对此线程安全对象(例如,字符串对象)的引用的类以及操作此类引用的方法

请参见下面的示例,以说明说明:

public class User {
   private string name;

   public User(String name) {
      this.name=name;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name=name;
   }
}
因此,即使String是一个不可变且线程安全的类,上面的类User中对它的引用也不是线程安全的,因为它的方法可以同时将该引用更改为新的String对象

如果您希望它是线程安全的,那么有很多选择。其中之一是将所有可以更改名称对象的方法设置为synchronized

不可变类型(在任何语言中)是特殊的引用类型。 它们的独特性在于,当它们被更改时,它们会被一个全新的实例替换,该实例反映了以前的状态+更改

假设两个线程运行一个函数,该函数接收一个不可变的引用类型对象作为参数(当然,本例中我将使用string)

//伪代码

  main() 
  {
      var str = "initialState";  
      new Thread(Do,str,1).Start();
      new Thread(Do,str,2).Start();
  }

  void Do(string arg,int tid)
  {
      int i = 0; 
      while(true)
      {
          arg += "running in thread " + tid + "for the " + i + "time";
          Console.WriteLine(arg);
      }
   }
该程序在并行打印时,在不影响其他线程中打印内容的情况下,在每个线程中运行的事件数

为什么?

如果您认为string是一种引用类型,那么它是通过引用而不是通过值传递的,这意味着它不是复制的,只有引用的副本才会发生。 尽管它最初是同一个物体。在第一次更改之后,它将不再存在,并创建一个不同的更改。 如果更改后它仍然是同一个对象,则它将是两个线程之间的共享资源,并将破坏这些线程无法打印的状态。

如果存在可以“更改”的“共享引用”,则不是该对象不是线程安全的,而是该引用可能不安全。这并不意味着物体不安全。