String运算符+号的底层实现

60 阅读2分钟

String的+运算符,底层实现是通过StringBuilder.append()方法来实现的。

但是StringBuilder不是线程安全的,若要在多线程环境下实现程序的正确性,有以下几种方法:

  1. 使用StringBuffer类;
  2. 手动同步 StringBuilder 的操作,使用synchronized关键字;
  3. 使用ThreadLocal,每个线程都有自己的局部StringBuilder变量

以下是一个StringBuilder在多线程场景下会出现的问题示例:

/**
 * 1. 验证使用线程不安全的StringBuilder类会产生的后果:输出结果会错乱,每次输出的Final result length 都不一样
 * 2. 使用线程安全的StringBuffer类不会有这种问题,输出的Final result length固定为24000
 * 3. 如果要使用线程不安全的StringBuilder类,需要使用synchronized关键字来保证线程安全
 * 4. 为什么要使用线程安全的StringBuffer类:StringBuilder 的方法(如 append, delete, insert, replace 等)都没有进行同步(synchronized),因此如果多个线程同时访问并操作同一个 StringBuilder 实例,会导致数据不一致或出现其他意想不到的行为。
 */
public class StringBuilderExample {
    //线程不安全的
        private static StringBuilder sb = new StringBuilder();
    //线程安全
//    private static StringBuffer sb = new StringBuffer();

    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                synchronized (sb) {
                    sb.append(Thread.currentThread().getName()).append(" ");
                }
            }
        };

        Thread thread1 = new Thread(task, "Thread1");
        Thread thread2 = new Thread(task, "Thread2");
        Thread thread3 = new Thread(task, "Thread3");

        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();

        // 输出结果
        System.out.println("Final result length: " + sb.length());
        System.out.println("Final result: " + sb);
    }
}

StringBuffer和StringBuilder的区别主要体现在线程安全性和性能上,用法基本相同,以下表格是详细对比:

 

特性StringBufferStringBuilder
线程安全性
性能较低(多线程场景适合)较高(单线程场景适合)
同步机制使用synchronized无同步
适用场景多线程环境单线程环境