Java字符串线程安全吗?
时间:2020-01-09 10:34:53 来源:igfitidea点击:
在多线程环境中,共享对象可以由任何线程修改,在某些情况下,我们可能需要确保线程之间共享的原始对象保持不变。可以通过使该对象不可变来实现。由于Java中的String在设计上是不可变的,因此它也是线程安全的,因此可以在许多线程之间安全地共享字符串对象。
Java String不变性和线程安全
需要注意的重要一点是,即使String是不可变的,因此是线程安全的,对String对象的引用也不是线程安全的。
如果将String对象传递给线程,并在线程中对其进行了修改,则将创建新的String并更改引用,但原始String保持不变。我们将通过一个示例来澄清这一点。
在示例中,字符串对象在三个线程之间共享。在执行这些线程时,共享字符串对象将通过在其后面添加内容来进行修改。当所有线程完成后,在主线程中再次打印字符串对象,以验证其是否保持不变。
public class StringThreadSafeExp implements Runnable {
private String str;
public StringThreadSafeExp(String str){
this.str = str;
}
@Override
public void run() {
System.out.println("Executing Thread- " + Thread.currentThread().getName());
// Adding to String
str = str + " World";
System.out.println("Modified String " + str);
}
public static void main(String[] args) {
String str = "Hello";
Thread t1 = new Thread(new StringThreadSafeExp(str));
Thread t2 = new Thread(new StringThreadSafeExp(str));
Thread t3 = new Thread(new StringThreadSafeExp(str));
t1.start();
t2.start();
t3.start();
// Wait for all threads to terminate
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Original String is " + str);
}
}
输出:
Executing Thread- Thread-2 Executing Thread- Thread-1 Executing Thread- Thread-0 Modified String Hello World Modified String Hello World Modified String Hello World Original String is Hello
如我们所见,每个线程在修改传递的String时都会引用指向指向修改内容的新String对象,而原始字符串则保持不变。
Java String的不变性确保String一旦赋值,就无法修改。通过使用可变的StringBuffer对象,我们可以验证在线程之间共享和修改可变对象时发生的情况。
public class StringThreadSafeExp implements Runnable {
private StringBuffer sb;
public StringThreadSafeExp(StringBuffer sb){
this.sb = sb;
}
@Override
public void run() {
System.out.println("Executing Thread- " + Thread.currentThread().getName());
// Adding to String
sb.append(" World");
System.out.println("Modified String " + sb);
}
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello");
Thread t1 = new Thread(new StringThreadSafeExp(sb));
Thread t2 = new Thread(new StringThreadSafeExp(sb));
Thread t3 = new Thread(new StringThreadSafeExp(sb));
t1.start();
t2.start();
t3.start();
// Wait for all threads to terminate
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Original String is " + sb);
}
}
输出:
Executing Thread- Thread-0 Executing Thread- Thread-2 Executing Thread- Thread-1 Modified String Hello World World Modified String Hello World Modified String Hello World World World Original String is Hello World World World
如我们现在所见,原始的StringBuffer对象本身被修改为可变的。

