StringBuffer和StringBuilder的線程安全性解析

一、概述

在java開發(fā)時,我們經常會用到StringBuffer和StringBuilder,且都知道一個結論:StringBuilder不是線程安全的,StringBuffer是線程安全的,至于為什么?可能大多數人一知半解。
下面,我通過代碼舉例、StringBuffer和StringBuilder源碼分析進行解釋。

二、代碼舉例

1、驗證StringBuffer是線程安全的

    /**
     * 驗證StringBuffer線程安全,如下,如果length==1000,則可證明
     * @throws InterruptedException
     */
    public static void testStringBuffer() throws InterruptedException {
        StringBuffer sb = new StringBuffer();
        for (int i=0; i<10; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j=0; j<1000; j++){
                        sb.append("a");

                    }
                }
            }).start();
        }

        Thread.sleep(100);
        System.out.println(sb.length());
    }

/**
     * 主測試方法
     * @param args
     */
  public static void main(String[] args) {
        try {
            ThreadTest.testStringBuffer();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

上面,我們起10個線程,每個線程循環(huán)1000次往StringBuffer對象里面append字符。理論上應該輸出實例sb的字符串長度=10000,我們執(zhí)行代碼,實際輸出也是10000,業(yè)務上證明了StringBuffer是線程安全的。

StringBuffer.png

2、驗證StringBuilder是線程不安全的

    /**
     * 驗證StringBuild線程不安全,如下,如果length!=1000,則可證明
     * @throws InterruptedException
     */
    public static void  testStringBuild() throws InterruptedException {
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<10; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j=0; j<1000; j++){
                        sb.append("a");
                    }
                }
            }).start();
        }

        Thread.sleep(100);
        System.out.println(sb.length());

    }

/**
     * 主測試方法
     * @param args
     */
  public static void main(String[] args) {
        try {
            ThreadTest.testStringBuild();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

上面,我們也起10個線程,每個線程循環(huán)1000次往StringBuilder對象里面append字符。我們也希望像StringBuffer一樣,得到10000的結果,但是我們運行代碼后,結果卻<10000。業(yè)務上證明了StringBuilder是線程不安全的。

StringBuilder.png

三、源碼分析

我們通過查看StringBuffer和StringBuilder的append()方法,發(fā)現他們都調用父類AbstractStringBuilder的append()方法,分別如下:

StringBuffer重寫的append方法:

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

StringBuilder重寫的append方法:

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

父類AbstractStringBuilder的append()方法:

   public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

通過上面的源碼,可知,StringBuffer和StringBuilder的append()的區(qū)別就是StringBuffer多了個 toStringCache = null; 這里,我們不再分析AbstractStringBuilder的append()方法的實現方式,大家可以自行了解,下面主要分析影響線程安全性的這段代碼的作用。

我們查看StringBuffer源碼,發(fā)現多了比StringBuilder多了一個參數:

 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;
  //其他代碼,略
}

再看下StringBuffer的toString方法:

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

這里的作用就是如果StringBuffer對象此時存在toStringCache,在多次調用其toString方法時,其new出來的String對象是會共享同一個char[] 內存的,達到共享的目的。但是StringBuffer只要做了修改,其toStringCache屬性值都會置null處理。這也是StringBuffer和StringBuilder的一個區(qū)別點,也是StringBuffer為什么線程安全的原因。

四、結論

通過上面的舉例和源碼分析,我們可以知道為什么StringBuffer是線程安全的,StringBuilder是線程不安全的,至于他們的append()方法,都是集成父類的append()方法,大家可以網上去了解下具體實現原理。

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容