【发布时间】:2019-02-27 16:30:21
【问题描述】:
字符串是不可变的,这意味着一旦你修改了值,它就会创建一个新的引用,并保持之前的引用值不变。
但是,当有人在争论时,我不明白:
字符串是线程安全的,因为它们是不可变的
考虑下面的代码:
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-result 是线程安全的。
恕我直言,不变性不能保证线程安全。
有人可以向我解释一下字符串是如何线程安全的吗?
更新:
感谢您的回答,我知道每个字符串都可以是线程安全的,但我的意思是,当您在其他方法中使用它们时,线程安全和不变性之间没有直接关系。
例如,不可变对象可以在有状态对象中使用并以非线程安全的结果结束,而可变对象也可以在同步方法中使用并以线程安全的结果结束。
【问题讨论】:
-
A 字符串是不可变的,因此是线程安全的。但是您没有使用 a 字符串,而是创建了一大堆 new 字符串。
-
仅仅因为你使用了String,并不意味着你“继承”了它的所有优点。 您的 代码不是线程安全的,但这与 String 本身无关。所以在这个例子中你需要确保
str = str +"1";不会被多个执行者同时执行。 -
特别是
str引用不是不可变的,每次重新分配它的值时都会改变它。由于您在没有同步或互斥锁的线程之间共享可变状态,因此结果不安全。 -
只使用线程安全的对象并不能使你的代码线程安全。
标签: java multithreading thread-safety