• StringBuffer与StringBulider的区别?来看看源码


    我们都知道字符串操作类面试极大概率问到的就是StringBuffer与StringBulider的区别,有关于线程安全,效率高,安全性如何?同步与否?等等问题都可能会出现,很多刚找工作的兄弟们是不是背着八股文自己都不知道为什么是这样?

    当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。

     那么问题来了:

    1、什么是线程安全?什么叫同步?

    2、为什么StringBuffer的方法是线程同步的而StringBulider不是?

    3、为什么二者之间StringBulider的速率比较高?

    1、什么是线程安全?什么叫同步?

    这个问题很简单,学过操作系统的兄弟们都知道多进程,而线程是进程的一个子单元,共享一个进程的资源,它们同步或者异步执行完成整个进程所需要完成的工作。现在的计算机大部分都是多道批处理的操作系统,多核的CPU足够的内存完全支持多进程任务的并发。那么在同一个进程下的多个线程的资源共享机制如果没有一定的限制就会出现不安全的现象。举个例子:类似于数据库幻读。当一个资源需要应用程序单独进行改变时,却发现其他的进程或者线程和你一起访问这个资源,那么修改就会出现问题,我还没使用你就给我改掉了?线程安全的概念就是保证多线程正确且正常的执行。

    这时候为了应对同时操作现象的发生,同步至关重要,再举个例子:数据库表记录加锁。什么是锁?分为乐观锁与悲观锁甚至因为大小作用又有其他的锁自旋锁,轻量级锁等等。但是无非就是保证数据的正确性,当一个线程在访问一个资源时,其他的线程只能读取不能修改,删除直到这个线程执行结束。可读不可写。同步关键字synchronized就是这个作用。

    2、为什么StringBuffer的方法是线程同步的而StringBulider不是?

    上面知道同步关键字synchronized就是声明某一个方法是线程安全的。那么我们就会猜测是不是因为StringBuffer的方法里有被synchronized修饰的呢?而StringBulider却没有?

    看看StringBuffer源码:

    1. public final class StringBuffer
    2. extends AbstractStringBuilder
    3. implements Serializable, Comparable, CharSequence
    4. {
    5. private transient String toStringCache;
    6. @Serial
    7. static final long serialVersionUID = 3388685877147921107L;
    8. @IntrinsicCandidate
    9. public StringBuffer() {
    10. super(16);
    11. }
    12. @IntrinsicCandidate
    13. public StringBuffer(int capacity) {
    14. super(capacity);
    15. }
    16. @IntrinsicCandidate
    17. public StringBuffer(String str) {
    18. super(str);
    19. }
    20. public StringBuffer(CharSequence seq) {
    21. super(seq);
    22. }
    23. @Override
    24. public synchronized int compareTo(StringBuffer another) {
    25. return super.compareTo(another);
    26. }
    27. @Override
    28. public synchronized int length() {
    29. return count;
    30. }
    31. @Override
    32. public synchronized int capacity() {
    33. return super.capacity();
    34. }
    35. @Override
    36. public synchronized void ensureCapacity(int minimumCapacity) {
    37. super.ensureCapacity(minimumCapacity);
    38. }
    39. @Override
    40. public synchronized void trimToSize() {
    41. super.trimToSize();
    42. }
    43. @Override
    44. public synchronized void setLength(int newLength) {
    45. toStringCache = null;
    46. super.setLength(newLength);
    47. }
    48. @Override
    49. public synchronized char charAt(int index) {
    50. return super.charAt(index);
    51. }
    52. @Override
    53. public synchronized int codePointAt(int index) {
    54. return super.codePointAt(index);
    55. }
    56. ...........省略.....
    57. }

    通过这一段源码我们不难发现一些特征:

    继承父类   AbstractStringBuilder 

     private transient String toStringCache;   缓存有关。

    @IntrinsicCandidate
        public StringBuffer() {
            super(16);
        }   默认容量16

       
        @IntrinsicCandidate
        public StringBuffer(int capacity) {
            super(capacity);
        }  可自定义容量

    几乎所有的字符串操作方法里都含有synchronized关键字包裹。

    再看看StringBulider的源码:

    1. public final class StringBuilder
    2. extends AbstractStringBuilder
    3. implements java.io.Serializable, Comparable, CharSequence
    4. {
    5. @Serial
    6. static final long serialVersionUID = 4383685877147921099L;
    7. @IntrinsicCandidate
    8. public StringBuilder() {
    9. super(16);
    10. }
    11. @IntrinsicCandidate
    12. public StringBuilder(int capacity) {
    13. super(capacity);
    14. }
    15. @IntrinsicCandidate
    16. public StringBuilder(String str) {
    17. super(str);
    18. }
    19. public StringBuilder(CharSequence seq) {
    20. super(seq);
    21. }
    22. @Override
    23. public int compareTo(StringBuilder another) {
    24. return super.compareTo(another);
    25. }
    26. @Override
    27. public StringBuilder append(Object obj) {
    28. return append(String.valueOf(obj));
    29. }
    30. @Override
    31. @IntrinsicCandidate
    32. public StringBuilder append(String str) {
    33. super.append(str);
    34. return this;
    35. }
    36. public StringBuilder append(StringBuffer sb) {
    37. super.append(sb);
    38. return this;
    39. }
    40. @Override
    41. public StringBuilder append(CharSequence s) {
    42. super.append(s);
    43. return this;
    44. }
    45. @Override
    46. public StringBuilder append(CharSequence s, int start, int end) {
    47. super.append(s, start, end);
    48. return this;
    49. }
    50. @Override
    51. public StringBuilder append(char[] str) {
    52. super.append(str);
    53. return this;
    54. }
    55. @Override
    56. public StringBuilder append(char[] str, int offset, int len) {
    57. super.append(str, offset, len);
    58. return this;
    59. }
    60. @Override
    61. public StringBuilder append(boolean b) {
    62. super.append(b);
    63. return this;
    64. }
    65. @Override
    66. @IntrinsicCandidate
    67. public StringBuilder append(char c) {
    68. super.append(c);
    69. return this;
    70. }
    71. @Override
    72. @IntrinsicCandidate
    73. public StringBuilder append(int i) {
    74. super.append(i);
    75. return this;
    76. }
    77. .......省略......
    78. }

    我们不难发现继承的父类与StringBuffer一样,默认的初始容量也是一样的,但是!它的方法都没有用synchronized关键字修饰。所以它不能保证线程安全。但是它正是因为不是同步的那么操作它这个对象的线程不用排队,会非常快的执行,在单进程的情况下(单应用程序)这个StringBulider肯定比StringBuffer速率高。

     至于父类的代码我们就不看了,看到最上面你会发现String这个final类几乎可以算得上这俩的爷爷辈。有兴趣的小伙伴自行研究哈!

  • 相关阅读:
    【面试:并发篇36:多线程:设计模式】享元模式-应用:自定义连接池
    Flowable实战(二):表结构以及变量表单介绍
    C语言每日一题(13) 单身狗1,2
    NFT Insider#105:The Sandbox即将参加韩国区块链周,YGG的声誉和进步(RAP)将引领玩家晋升到下一层级
    CSP初赛知识精讲--容斥原理
    MST2100是一款用于摩托车单相磁电机 调压器的控制IC
    S-Clustr(影子集群) 重磅更新!黑入工业PLC设备!
    动手学深度学习_全卷积网络 FCN
    记一次清理挖矿病毒的过程
    一次cpu 跌底排查
  • 原文地址:https://blog.csdn.net/m0_59588838/article/details/126361554