欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java StringBuffer與StringBuilder有什么區(qū)別

 更新時(shí)間:2023年01月18日 10:20:41   作者:hudawei996  
當(dāng)對(duì)字符串進(jìn)行修改的時(shí)候,需要使用 StringBuffer 和 StringBuilder類,和String類不同的是,StringBuffer和 StringBuilder類的對(duì)象能夠被多次的修改,并且不產(chǎn)生新的未使用對(duì)象,本篇我們來分析分析它們的區(qū)別

一問道StringBuffer與StringBuilder的區(qū)別,張口就來StringBuffer是線程安全的,因?yàn)樗嚓P(guān)方法都加了synchronized 關(guān)鍵字,StringBuilder線程不安全。沒錯(cuò),確實(shí)如此,但是我們查看過源碼會(huì)發(fā)現(xiàn)StringBuffer是從jdk1.0就開始了,StringBuilder是從jdk1.5開始的。于是我就產(chǎn)生這樣一個(gè)疑問,既然已經(jīng)有了StringBuffer,為什么jdk5又出了一個(gè)StringBuilder呢,也就是單線程時(shí)候StringBuffer與StringBuilder有什么區(qū)別。

一、StringBuffer與StringBuilder的共同之處

1、都繼成了AbstractStringBuilder這個(gè)抽象類,實(shí)現(xiàn)了CharSequence接口

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

2、其append方法都是 super.append(str),調(diào)用了父類AbstractStringBuilder的append(String str)方法

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

3、初始容量都是16和擴(kuò)容機(jī)制都是"舊容量*2+2"

4、底層都是用char[]字符數(shù)組實(shí)現(xiàn),且字符數(shù)組都是可變的,這點(diǎn)不同于String

二、StringBuffer與StringBuilder的不同之處

  • StringBuffer多線程安全的,StringBuilder多線程不安全
  • StringBuffer從JDK1.0就有了,StringBuilder是JDK5.0才出現(xiàn)
  • StringBuffer比StringBuilder多了一個(gè)toStringCache字段,用來在toString方法中進(jìn)行緩存,每次append操作之前都先把toStringCache設(shè)置為null,若多次連續(xù)調(diào)用toString方法,可避免每次Arrays.copyOfRange(value, 0, count)操作,節(jié)省性能。
 @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    @Override
    public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

4、由于StringBuilder沒有考慮同步,在單線程情況下,StringBuilder的性能要優(yōu)于StringBuffer

三、單線程StringBuffer與StringBuilder區(qū)別

這個(gè)才是我們重點(diǎn)討論的,單線程下StringBuffer加了synchronized,雖然是單線程, 但是synchronized獲取鎖和釋放鎖也還是需要時(shí)間的, 而StringBuilder沒有,這個(gè)就是重點(diǎn)區(qū)別。因此重點(diǎn)要討論synchronized鎖的狀態(tài),從獲取鎖到釋放鎖的過程,因此需要討論一下鎖的升級(jí)和優(yōu)化。

鎖的4中狀態(tài):無鎖狀態(tài)、偏向鎖狀態(tài)、輕量級(jí)鎖狀態(tài)、重量級(jí)鎖狀態(tài)(級(jí)別從低到高)

(1)偏向鎖:

偏向鎖是指一段同步代碼一直被一個(gè)線程所訪問,那么該線程會(huì)自動(dòng)獲取鎖。降低獲取鎖的代價(jià)。

為什么要引入偏向鎖?

因?yàn)榻?jīng)過HotSpot的作者大量的研究發(fā)現(xiàn),大多數(shù)時(shí)候是不存在鎖競爭的,常常是一個(gè)線程多次獲得同一個(gè)鎖,因此如果每次都要競爭鎖會(huì)增大很多沒有必要付出的代價(jià),為了降低獲取鎖的代價(jià),才引入的偏向鎖。

偏向鎖的升級(jí)

當(dāng)線程1訪問代碼塊并獲取鎖對(duì)象時(shí),會(huì)在java對(duì)象頭和棧幀中記錄偏向的鎖的threadID,因?yàn)槠蜴i不會(huì)主動(dòng)釋放鎖,因此以后線程1再次獲取鎖的時(shí)候,需要比較當(dāng)前線程的threadID和Java對(duì)象頭中的threadID是否一致,如果一致(還是線程1獲取鎖對(duì)象),則無需使用CAS來加鎖、解鎖;如果不一致(其他線程,如線程2要競爭鎖對(duì)象,而偏向鎖不會(huì)主動(dòng)釋放因此還是存儲(chǔ)的線程1的threadID),那么需要查看Java對(duì)象頭中記錄的線程1是否存活,如果沒有存活,那么鎖對(duì)象被重置為無鎖狀態(tài),其它線程(線程2)可以競爭將其設(shè)置為偏向鎖;如果存活,那么立刻查找該線程(線程1)的棧幀信息,如果還是需要繼續(xù)持有這個(gè)鎖對(duì)象,那么暫停當(dāng)前線程1,撤銷偏向鎖,升級(jí)為輕量級(jí)鎖,如果線程1 不再使用該鎖對(duì)象,那么將鎖對(duì)象狀態(tài)設(shè)為無鎖狀態(tài),重新偏向新的線程。

偏向鎖的取消:

偏向鎖是默認(rèn)開啟的,而且開始時(shí)間一般是比應(yīng)用程序啟動(dòng)慢幾秒,如果不想有這個(gè)延遲,那么可以使用-XX:BiasedLockingStartUpDelay=0;

如果不想要偏向鎖,那么可以通過-XX:-UseBiasedLocking = false來設(shè)置;

(2)輕量級(jí)鎖

輕量級(jí)鎖是指當(dāng)鎖是偏向鎖的時(shí)候,被另一個(gè)線程所訪問,偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖,其他線程會(huì)通過自旋的形式嘗試獲取鎖,不會(huì)阻塞,提高性能

為什么要引入輕量級(jí)鎖?

輕量級(jí)鎖考慮的是競爭鎖對(duì)象的線程不多,而且線程持有鎖的時(shí)間也不長的情景。因?yàn)樽枞€程需要CPU從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),代價(jià)較大,如果剛剛阻塞不久這個(gè)鎖就被釋放了,那這個(gè)代價(jià)就有點(diǎn)得不償失了,因此這個(gè)時(shí)候就干脆不阻塞這個(gè)線程,讓它自旋這等待鎖釋放。

(3)重量級(jí)鎖

重量級(jí)鎖是指當(dāng)鎖為輕量級(jí)鎖的時(shí)候,另一個(gè)線程雖然是自旋,但自旋不會(huì)一直持續(xù)下去,當(dāng)自旋一定次數(shù)的時(shí)候,還沒有獲取到鎖,就會(huì)進(jìn)入阻塞,該鎖膨脹為重量級(jí)鎖。重量級(jí)鎖會(huì)讓其他申請(qǐng)的線程進(jìn)入阻塞,性能降低。

輕量級(jí)鎖什么時(shí)候升級(jí)為重量級(jí)鎖?

線程1獲取輕量級(jí)鎖時(shí)會(huì)先把鎖對(duì)象的對(duì)象頭MarkWord復(fù)制一份到線程1的棧幀中創(chuàng)建的用于存儲(chǔ)鎖記錄的空間(稱為DisplacedMarkWord),然后使用CAS把對(duì)象頭中的內(nèi)容替換為線程1存儲(chǔ)的鎖記錄(DisplacedMarkWord)的地址;

如果在線程1復(fù)制對(duì)象頭的同時(shí)(在線程1CAS之前),線程2也準(zhǔn)備獲取鎖,復(fù)制了對(duì)象頭到線程2的鎖記錄空間中,但是在線程2CAS的時(shí)候,發(fā)現(xiàn)線程1已經(jīng)把對(duì)象頭換了,線程2的CAS失敗,那么線程2就嘗試使用自旋鎖來等待線程1釋放鎖。

但是如果自旋的時(shí)間太長也不行,因?yàn)樽孕且腃PU的,因此自旋的次數(shù)是有限制的,比如10次或者100次,如果自旋次數(shù)到了線程1還沒有釋放鎖,或者線程1還在執(zhí)行,線程2還在自旋等待,這時(shí)又有一個(gè)線程3過來競爭這個(gè)鎖對(duì)象,那么這個(gè)時(shí)候輕量級(jí)鎖就會(huì)膨脹為重量級(jí)鎖。重量級(jí)鎖把除了擁有鎖的線程都阻塞,防止CPU空轉(zhuǎn)。

*注意:為了避免無用的自旋,輕量級(jí)鎖一旦膨脹為重量級(jí)鎖就不會(huì)再降級(jí)為輕量級(jí)鎖了;偏向鎖升級(jí)為輕量級(jí)鎖也不能再降級(jí)為偏向鎖。一句話就是鎖可以升級(jí)不可以降級(jí),但是偏向鎖狀態(tài)可以被重置為無鎖狀態(tài)。

綜上可知,StringBuffer雖然是單線程,但它是有偏向鎖升級(jí)過程判斷的,會(huì)耗費(fèi)時(shí)間,效率固然低于StringBuilder

四、StringBuffer與StringBuilder的應(yīng)用場景

1、StringBuffer多線程安全,但是加了synchronized,其效率低。故適用于多線程下,并發(fā)量不是很高的場景

2、StringBuilder沒有加任何鎖,其效率高,適用單線程場景,但同時(shí)也適用于高并發(fā)場景中,提高高并發(fā)場景下程序的響應(yīng)性能,至于線程安全問題可以通過其它手段解決,如ThreadLocal,CAS操作等。

3、所以對(duì)于高并發(fā)場景下,若有用到二者,還是建議優(yōu)先使用StringBuilder的

到此這篇關(guān)于Java StringBuffer與StringBuilder有什么區(qū)別的文章就介紹到這了,更多相關(guān)Java StringBuffer與StringBuilder內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解SpringBoot如何優(yōu)雅的進(jìn)行前后端通信

    詳解SpringBoot如何優(yōu)雅的進(jìn)行前后端通信

    現(xiàn)在的項(xiàng)目基本上都是前后端分離的項(xiàng)目,如何打通前后端,接收前端傳過來的參數(shù)呢,下面小編就來和大家詳細(xì)介紹一下SpringBoot如何優(yōu)雅的進(jìn)行前后端通信
    2024-03-03
  • springboot項(xiàng)目(jar包)指定配置文件啟動(dòng)圖文教程

    springboot項(xiàng)目(jar包)指定配置文件啟動(dòng)圖文教程

    這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目(jar包)指定配置文件啟動(dòng)的相關(guān)資料,在多環(huán)境部署過程中、及線上運(yùn)維中可能會(huì)遇到臨時(shí)指定配置文件的情況,需要的朋友可以參考下
    2023-07-07
  • Java基礎(chǔ)之異常處理操作示例

    Java基礎(chǔ)之異常處理操作示例

    這篇文章主要介紹了Java基礎(chǔ)之異常處理操作,涉及java異常捕獲、拋出異常、自定義異常處理相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • 關(guān)于JAVA8的 Stream學(xué)習(xí)

    關(guān)于JAVA8的 Stream學(xué)習(xí)

    這篇文章主要介紹了JAVA8 Stream學(xué)習(xí)方法的相關(guān)資料,需要的朋友可以參考下面文章內(nèi)容
    2021-09-09
  • 解決spring-boot2.0.6中webflux無法獲得請(qǐng)求IP的問題

    解決spring-boot2.0.6中webflux無法獲得請(qǐng)求IP的問題

    這幾天在用 spring-boot 2 的 webflux 重構(gòu)一個(gè)工程,寫到了一個(gè)需要獲得客戶端請(qǐng)求 IP 的地方,在寫的過程中遇到很多問題,下面小編通過一段代碼給大家介紹解決spring-boot2.0.6中webflux無法獲得請(qǐng)求IP的問題,感興趣的朋友跟隨小編一起看看吧
    2018-10-10
  • 詳解Java比較器

    詳解Java比較器

    這篇文章主要介紹了Java比較器的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Android 應(yīng)用按返回鍵退向后臺(tái)運(yùn)行實(shí)例代碼

    Android 應(yīng)用按返回鍵退向后臺(tái)運(yùn)行實(shí)例代碼

    這篇文章主要介紹了Android 應(yīng)用按返回鍵退向后臺(tái)運(yùn)行實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • IntelliJ IDEA 2020.3 重大特性(新功能一覽)

    IntelliJ IDEA 2020.3 重大特性(新功能一覽)

    這篇文章主要介紹了IntelliJ IDEA 2020.3 重大特性(新功能一覽),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Java中的15種鎖

    Java中的15種鎖

    在讀很多并發(fā)文章中,會(huì)提及各種各樣鎖如公平鎖,樂觀鎖等等,這篇文章小編將向大家介紹是各種鎖的分類,感興趣的小伙伴可以參考下面文章的具體內(nèi)容
    2021-09-09
  • java應(yīng)用開發(fā)之Mybatis通過Mapper代理自定義接口的實(shí)現(xiàn)

    java應(yīng)用開發(fā)之Mybatis通過Mapper代理自定義接口的實(shí)現(xiàn)

    這篇文章主要介紹了java應(yīng)用開發(fā)之Mybatis通過Mapper代理自定義接口的實(shí)現(xiàn)方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-09-09

最新評(píng)論