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对象本身被修改为可变的。