答:StringBuffer 是线程安全的(synchronized),而 StringBuilder不是,所以 StringBuilder 效率更高,锁的获取和释放会带来开销。

看看代码

不论是创建 StringBuffer 还是 StringBuilder对象,都是创建一个容量为16的字符数组。

/**
* The value is used for character storage.
*/
char[] value;

/**
* The count is the number of characters used.
*/
int count;

AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

区别就是所有的方法中,比如append,前者有synchronized关键字修饰。

StringBuffer的append方法:

public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

StringBuilder的append方法:

public StringBuilder append(String str) {
    super.append(str);
    return this;
}

虽然实际的实现是一样的。

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull(); // 如果是null的话,就添加字符串"null"
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count); // 字符数组的拷贝
    count += len;
    return this;
}

toString()方法

虽然StringBuffer使用了缓存,但是本质上都一样,每次toString()都会创建一个新的String对象,而不是使用底层的字符数组,我的理解是:StringBuffer/StringBuilder的存在是为了高效的操作字符串(字符数组)的状态,但是当我们使用toString()的时候一定是一个稳定的状态,具有确切的行为,底层的字符数组仍然是可有变化的。

StringBuffer:
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

StringBuilder:
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

参考

StringBuffer 和 StringBuilder 的区别是什么?

String StringBuffer 和 StringBuilder 的区别是什么? String 为什么是不可变的?

Java中的String vs StringBuilder vs StringBuffer

String如何改变一个字符串内容但是不创建新的对象?