字符串是不可变的,这意味着一旦修改该值,它就会创建一个新的引用并保留先前的引用值不变。
但是,当有人争论时我不明白:
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对象)可以在有状态对象中使用,并以非线程安全结果结束,可变对象也可以在同步方法中使用,并以线程安全结果结束。
最佳答案
我认为可以概括如下:
- 对
String
对象的操作是线程安全的。 (它们是线程安全的,因为String
对象是不可变的,但原因与您的示例没有直接关系。) - 非
final
共享2变量上的不同步读写操作1不是线程安全的,无论变量的类型如何.
您的示例执行str = str + 1;
。它将对 String
对象的操作与对非同步共享变量 (str
) 的操作结合起来。由于后者,它不是线程安全的。
1 - 更准确地说,写入和读取之间没有发生在之间的关系,以保证所需的内存可见性属性,并且没有锁定来保证所需的原子性属性。 (“必需”是指算法正确性所必需的...)
2 - 共享意味着多个线程可见并被多个线程使用。如果一个变量仅对一个线程可见或由一个线程使用,则称该变量是线程受限的,并且实际上不被共享。
关于java - String线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54910117/