java - String线程安全吗?

标签 java multithreading thread-safety

字符串是不可变的,这意味着一旦修改该值,它就会创建一个新的引用并保留先前的引用值不变。

但是,当有人争论时我不明白:

Strings are thread safe as they are immutable

考虑下面的代码:

private String str = "1";
ExecutorService executorService = Executors.newFixedThreadPool(10);
IntStream.range(0, 1000).forEach((i)-> executorService.submit(()-> {
    str = str +"1";
}));

executorService.awaitTermination(10, TimeUnit.SECONDS);

System.out.println(str.length());

如果它是线程安全的,那么它应该打印1001,而它总是打印小于预期值。

我知道上面的代码将创建 1001 个不可变引用,每个引用本身都是线程安全的,但作为开发人员,仍然不能使用不可变的东西并期望 end-结果将是线程安全的。

恕我直言,不变性不能保证线程安全。

有人可以向我解释一下字符串如何实现线程安全吗?

更新:

感谢您的回答,我知道每个字符串都可以是线程安全的,但我的观点是,当您在其他方法中使用它们时,线程安全性和不变性之间没有直接关系。

例如,不可变对象(immutable对象)可以在有状态对象中使用,并以非线程安全结果结束,可变对象也可以在同步方法中使用,并以线程安全结果结束。

最佳答案

我认为可以概括如下:

  1. String对象的操作是线程安全的。 (它们是线程安全的,因为 String 对象是不可变的,但原因与您的示例没有直接关系。)
  2. final共享2变量上的不同步读写操作1不是线程安全的,无论变量的类型如何.

您的示例执行str = str + 1;。它将对 String 对象的操作与对非同步共享变量 (str) 的操作结合起来。由于后者,它不是线程安全的。

<小时/>

1 - 更准确地说,写入和读取之间没有发生在之间的关系,以保证所需的内存可见性属性,并且没有锁定来保证所需的原子性属性。 (“必需”是指算法正确性所必需的...)

2 - 共享意味着多个线程可见并被多个线程使用。如果一个变量仅对一个线程可见或由一个线程使用,则称该变量是线程受限的,并且实际上不被共享。

关于java - String线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54910117/

相关文章:

multithreading - TPL 和 async/await 之间的区别(线程处理)

java - 线程安全的任务批处理

c++ - 多线程和使用事件

java - 关于从同步块(synchronized block)中调用方法

java - 在 IntelliJ IDE 中将 Spark 与 Scala 项目集成时出错

java - 使用分离轴定理找到 MTV(最小平移 vector )

c# - 使用任务,但用户界面仍然被阻止

multithreading - 为每个线程分配一个面板 - Delphi

java - PropertyConfigurator.configure 不适用于 spring

java - 将字符转换为其二进制值