面试题答案
一键面试Java String不可变性保证线程安全的原理
- 底层实现:Java 中
String
类被声明为final
,其内部的字符数组value
也是final
的。这意味着String
对象一旦创建,其内容就不能被修改。 - 线程安全:因为
String
不可变,多个线程同时访问同一个String
对象时,不会出现一个线程修改了String
的内容,而导致其他线程看到不一致状态的情况。多个线程可以安全地共享同一个String
实例。
可能出现的问题及不可变性的解决方式
- 问题示例:假设
String
是可变的,在多线程环境下,可能会出现以下情况。
public class StringMutabilityProblem {
private static String sharedString = "initial";
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
sharedString = sharedString + " - modified by thread1";
});
Thread thread2 = new Thread(() -> {
System.out.println("Thread 2 sees: " + sharedString);
});
thread1.start();
thread2.start();
}
}
在这个例子中,如果 String
是可变的,thread2
可能会打印出不一致的结果,因为 thread1
对 sharedString
的修改可能还未完成,thread2
就已经读取了该值。
- 不可变性的解决:由于
String
实际是不可变的,上述问题不会发生。当执行sharedString = sharedString + " - modified by thread1";
时,实际上是创建了一个新的String
对象,而原有的sharedString
对象并未改变。thread2
看到的sharedString
始终是原始的字符串,直到thread1
完成操作并将新的String
赋值给sharedString
。修改后的代码如下:
public class StringImmutabilitySolution {
private static final String sharedString = "initial";
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
String newString = sharedString + " - modified by thread1";
// 这里操作的是新创建的字符串对象,不影响原有的sharedString
});
Thread thread2 = new Thread(() -> {
System.out.println("Thread 2 sees: " + sharedString);
// 始终打印初始值,不受thread1操作影响
});
thread1.start();
thread2.start();
}
}
这样,通过 String
的不可变性,保证了多线程环境下的安全性。