IT人生

  • 首页
  • 归档
  • kafka
  • Java
  • Spring
  • Golang
  • SQL
  • Spark
  • ElasticSearch
  • 关于

  • 搜索
Phoenix HBase Kudu ElasticSearch Spring 数据结构 操作系统 Kettle Azkaban Sqoop Hive Yarn Redis Mybatis Impala Cloudera 大数据 HDFS mycat shell Linux 架构 并发 mysql sql golang java 工具 spark kafka 人生

JDK源码分析-StringBuffer和StringBuilder

发表于 2017-01-14 | 分类于 java | 0 | 阅读次数 1315

系列文章:

  1. JDK源码分析-transient关键字
  2. JDK源码分析-transient关键字
  3. JDK源码分析-String
  4. JDK源码分析-AbstractStringBuilder
  5. JDK源码分析-StringBuffer和StringBuilder
  6. JDK源码分析-RandomAccess
  7. JDK源码分析-ArrayList
  8. JDK源码分析-LinkedList
  9. JDK源码分析-HashMap
  10. JDK源码分析-HashSet
  11. JDK源码分析-LinkedHashMap
  12. JDK源码分析-ConcurrentHashMap

一.总览

StringBuffer 是在JDK1.0就引入了,因为String的不可变性(为什么Java中String是不可变的),字符串的拼接和裁剪等功能就会产生新的String对象,所以对性能有很大影响。 StringBuffer 是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,我们可以用 append 或者 add 方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer 本质是一个线程安全的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销。 StringBuilder是在JDK1.5引入的,在功能上和StringBuffer没有区别,但是去掉了线程安全部分,也就有效的减小了性能开销。

二.相同点

2.1 StringBuffer和StringBuilder有相同的继承结构

他们都继承了AbstractStringBuilder类,都实现了Serializable和CharSequence接口 stringbuffer-and-stringbuilder

2.2 StringBuffer和StringBuilder都是可变对象

他们底层都是利用可修改的char[]数据来存储对象(JDK1.9中是byte数组),且数组的最大长度MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8。 默认初始长度为16,每次append()的时候,都会校验当前数组长度是否足够,如果不够就会扩容。扩容会产生多重开销,因为要抛弃原有数组,创建新的数组(从源码newCapacity中看出,数组扩容是2*n+2),然后进行 arraycopy

    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

三.不同点

StringBuffer的所有方法都加上了synchronized方法,因此是线程安全的;StringBuilder的所有方法和StringBuffer相同,只是少了synchronized修饰,因此不是线程安全的,但是性能更好,所以在不要求线程安全的条件下,推荐使用StringBuilder

3.1 StringBuffer和StringBuilder性能测试

在较小数据量的情况下,二者差别不大

@State(Scope.Benchmark)
public static class MyState {
    int iterations = 1000;
    String initial = "abc";
    String suffix = "def";
}
 
@Benchmark
public StringBuffer benchmarkStringBuffer(MyState state) {
    StringBuffer stringBuffer = new StringBuffer(state.initial);
    for (int i = 0; i < state.iterations; i++) {
        stringBuffer.append(state.suffix);
    }
    return stringBuffer;
}
 
@Benchmark
public StringBuilder benchmarkStringBuilder(MyState state) {
    StringBuilder stringBuilder = new StringBuilder(state.initial);
    for (int i = 0; i < state.iterations; i++) {
        stringBuilder.append(state.suffix);
    }
    return stringBuilder;
}

使用默认的Throughput模式,单位时间次数如下:

Benchmark                                          Mode  Cnt      Score      Error  Units
StringBufferStringBuilder.benchmarkStringBuffer   thrpt  200  86169.834 ±  972.477  ops/s
StringBufferStringBuilder.benchmarkStringBuilder  thrpt  200  91076.952 ± 2818.028  ops/s

当把循环次数从1000增加到10000结果如下:

Benchmark                                          Mode  Cnt   Score   Error  Units
StringBufferStringBuilder.benchmarkStringBuffer   thrpt  200  77.178 ± 0.898  ops/s
StringBufferStringBuilder.benchmarkStringBuilder  thrpt  200  85.769 ± 1.966  ops/s

四.总结

StringBuffer是线程安全的,但是效率低
StringBuilder非线程安全,效率稍高

参考

  1. https://www.baeldung.com/java-string-builder-string-buffer
  2. https://www.baeldung.com/java-jvm-warmup
  3. http://www.eecg.toronto.edu/~yuan/papers/osdi16-hottub.pdf
  • 本文作者: Randy
  • 本文链接: http://www.itrensheng.com/archives/stringbufferstringbuilder
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# Phoenix # HBase # Kudu # ElasticSearch # Spring # 数据结构 # 操作系统 # Kettle # Azkaban # Sqoop # Hive # Yarn # Redis # Mybatis # Impala # Cloudera # 大数据 # HDFS # mycat # shell # Linux # 架构 # 并发 # mysql # sql # golang # java # 工具 # spark # kafka # 人生
JDK源码分析-AbstractStringBuilder
JDK源码分析-RandomAccess
  • 文章目录
  • 站点概览
Randy

Randy

技术可以暂时落后,但任何时候都要有上进的信念

80 日志
27 分类
31 标签
RSS
Github E-mail
Creative Commons
© 2021 备案号:沪ICP备19020689号-1
Randy的个人网站