StringBuffer和StringBuilder的区别与联系

文章目录

  • 区别一览
  • StringBuffer如何实现多线程
      • 同步关键字(Synchronized)
      • 性能考虑
      • 使用场景
  • 当不使用多线程的情况下,是否StringBuffer和StringBuilder的性能一样?
      • 性能差异原因
      • 实践中的选择
      • 结论

区别一览

StringBufferStringBuilder 在 Java 中都用于创建和操作字符串,但它们之间存在一些关键区别和联系:

  1. 同步性(线程安全):

    • StringBuffer 是线程安全的,这意味着它的方法是同步的。当在多线程环境中使用时,StringBuffer 会确保在任何时刻只有一个线程能够改变字符串的内容。
    • StringBuilder 不是线程安全的,这意味着它的方法不是同步的。因此,在单线程环境中使用 StringBuilder 可以提高性能,因为它避免了同步带来的开销。
  2. 性能:

    • 由于不需要进行线程同步,StringBuilder 通常比 StringBuffer 快,尤其是在字符串频繁修改的场景中。
  3. 用法:

    • 它们都继承自相同的父类 AbstractStringBuilder,并且提供了类似的方法,如 append(), insert(), delete(), reverse() 等,用于构造和修改字符串。
  4. 选择使用场景:

    • 在单线程应用程序或者**局部变量(栈封闭)**的场景中,推荐使用 StringBuilder
    • 在多线程环境中,如果字符串对象需要在多个线程间共享和修改,使用 StringBuffer
  5. 可变性:

    • 两者都是可变的,这意味着它们都允许在不创建新对象的情况下更改字符串的内容。这与 String 类型不同,String 类型的对象一旦创建,其内容就不可更改。

在实际应用中,选择 StringBuffer 还是 StringBuilder 应基于应用程序的线程安全需求。对于大多数现代应用程序,StringBuilder 由于其更高的性能而更受欢迎,但在需要确保线程安全的场合,StringBuffer 仍然是必需的。

StringBuffer如何实现多线程

可以看到StringBugffer中基本上很多方法都用了synchronized修饰。
在这里插入图片描述
下面是StringBuffer在的一些核心伪代码:

public final class StringBuffer implements java.io.Serializable, CharSequence {
    private char[] value;
    private int count;

    public synchronized StringBuffer append(String str) {
        // 检查容量并扩展
        int len = str.length();
        ensureCapacityInternal(count + len);
        
        // 将字符串复制到内部数组
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

    private synchronized void ensureCapacityInternal(int minimumCapacity) {
        // 如果当前容量不足,则进行扩展
        if (minimumCapacity - value.length > 0) {
            expandCapacity(minimumCapacity);
        }
    }

    private void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }
}

StringBuffer 在 Java 中实现多线程安全主要通过以下方式:

同步关键字(Synchronized)

  1. 方法级同步:

    • StringBuffer 类中,几乎所有公共方法都使用 synchronized 关键字进行声明。这意味着当一个线程正在执行这些同步方法时,其他线程必须等待,直到当前线程完成操作。
    • 举个例子,假设有一个 StringBuffer 对象 sb 和两个线程 A 和 B。如果线程 A 正在执行 sb.append("A"),而这个方法是同步的,那么线程 B 就必须等待,直到线程 A 完成操作才能执行 sb.append("B")
  2. 对象锁:

    • 当一个线程进入一个 StringBuffer 的同步方法时,它会自动获取该 StringBuffer 对象的锁。直到该线程退出同步方法,其他线程才能访问该对象的任何同步方法。
    • 这种锁是互斥的,确保同一时间只有一个线程能操作同一个 StringBuffer 实例。

性能考虑

  • 由于 synchronized 方法可能导致性能问题,尤其是在高度竞争的环境中,StringBuffer 在单线程应用或者没有线程安全需求的情况下并不是最佳选择。这种场景下,StringBuilder(不是线程安全的)通常是更好的选择,因为它避免了同步带来的性能损失。

使用场景

  • 尽管 StringBuffer 提供了线程安全,但在现代多线程应用程序中,通常推荐使用其他并发工具,例如 java.util.concurrent 包中的类,或者完全避免在多个线程间共享可变状态。这是因为精细的并发控制通常可以提供更好的性能和更易于管理的线程安全性。

综上所述,StringBuffer 通过使用 synchronized 关键字在方法级别提供线程安全,但这种方式可能会导致在高并发环境下的性能问题。在现代 Java 应用中,建议谨慎考虑是否需要使用 StringBuffer,以及是否有更适合的线程安全替代方案。

当不使用多线程的情况下,是否StringBuffer和StringBuilder的性能一样?

我们以append为例
可以看到
在这里插入图片描述
图片中的StringBuffer和StringBuilder都是用了同一个父类方法实现append,在返回this。

但是
当不使用多线程的情况下,StringBufferStringBuilder 的性能并不完全相同。尽管在单线程环境中,线程安全的问题不再是一个关注点,但 StringBuffer 的同步特性依然存在,这会导致一些性能上的差异。

性能差异原因

  1. 同步开销:

    • StringBuffer 中的大多数方法使用了 synchronized 关键字,这意味着即便在单线程环境中,每次调用这些方法时也会涉及到获取和释放对象锁的开销。这是一个额外的成本,哪怕只有一个线程在操作。
  2. StringBuilder 的优化:

    • StringBuilder 没有这些同步开销,因此在执行相同的字符串操作时,它通常会更快。即使在单线程应用中,这种性能差异在处理大量数据或进行频繁的字符串操作时仍然显著。

实践中的选择

  • 在单线程环境中,由于没有多线程并发问题,推荐使用 StringBuilder。它提供了与 StringBuffer 相同的 API,但由于避免了同步开销,性能更优。
  • 只有当确实需要在多线程环境中共享字符串构建器对象时,才应选择 StringBuffer

结论

尽管在不使用多线程的情况下,StringBufferStringBuilder 都能安全地使用,但 StringBuilder 由于没有同步开销,其性能通常更佳。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/153696.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity Quaternion接口API的常用方法解析_unity基础开发教程

Quaternion接口的常用方法 Quaternion.Euler()Quaternion.Lerp()Quaternion.Inverse()Quaternion.RotateTowards() Quaternion在Unity中是一种非常重要的数据类型&#xff0c;用于表示3D空间中的旋转。Quaternion可以表示任何旋转&#xff0c;无论是在哪个轴上旋转多少度&#…

fablic 矩形多边形展示删除按钮

标注的矩形框或者多边形框展示删除按钮&#xff1b; 官网有一个例子 我原本想着按照他这个思路&#xff0c;很简单的&#xff1b; 可是当我在使用的过程中&#xff0c;遇到了一些问题&#xff0c;多变想不展示删除按钮&#xff1b;并且如果之前有矩形&#xff0c;无法渲然删除按…

拿走吧你,Fiddler模拟请求发送和修改响应数据

fiddler模拟伪造请求 方法一&#xff1a;打断点模拟HTTP请求 1、浏览器页面填好内容后&#xff08;不要操作提交&#xff09;&#xff0c;打开fiddler&#xff0c;设置请求前断点&#xff0c;点击菜单fiddler,”Rules”\”Automatic Breakpoints”\”Before Requests” 2、在…

问题总结(持续更新)

Linux 1.虚拟机问题 打开虚拟机所在目录对 后缀 .vmx文件进行修改 vmcio.present"FALSE" 改为FALSE即可 2.因某些问题导致本来正常的虚拟机没有网络了 重新配置网络 vim /etc/sysconfig/network-scripts/ifcfg-enstab补全 service network restart 重启网络 Sentina…

海外推广必备|如何制定领英LinkedIn营销战略?

在网络上脱颖而出不是一件简单的事。不仅有比以往更多的平台、算法和内容类型&#xff0c;而且还有更多的企业在争夺注意力。据统计&#xff0c;每天有超过 270 万家公司在 LinkedIn 上发布信息。 策略很重要&#xff0c;尤其是在 LinkedIn 营销领域。下面将为你总结LinkedIn 营…

操作系统OS/进程与线程/线程

进程和线程 进程 进程实体&#xff08;进程映像&#xff09;由PCB、程序段和数据段组成&#xff0c;其中PCB是进程存在的唯一标志。 线程 线程最直接的理解就是“轻量级进程”&#xff0c;它是一个基本的CPU执行单元&#xff0c;包含CPU现场(状态)&#xff0c;也是程序执行…

uniapp Android如何打开常用系统设置页面?

uniapp Android 如何打开常用系统设置页面&#xff1f; 在使用App过程时&#xff0c;有时候会对一些权限获取&#xff0c;比如打开蓝牙、打开通知栏通知等设置&#xff0c;我们如何快速跳转到需要的设置页面&#xff1f; 文章目录 uniapp Android 如何打开常用系统设置页面&…

500mA 线性锂电充电芯片 DP4054/DP4054H完全兼容替代TP4054

锂电池是一种新型的可充电电池&#xff0c;其具有体积小、重量轻、容量大耐用性强等特点&#xff0c;因此被广泛应用于手机、笔记本电脑、移动电源等电了设备上。 充电原理是指电池在充电过程中&#xff0c;用电流将锂离子从外部电源输入电池&#xff0c;使其形成 一个电荷差&…

【LeetCode刷题-滑动窗口】--424.替换后的最长重复字符

424.替换后的最长重复字符 方法&#xff1a;滑动窗口 右边界先移动找到一个满足题意的可以替换k个字符以后&#xff0c;所有字符都变成一样的当前看来最小的子串&#xff0c;直到右边界纳入一个字符以后&#xff0c;不能满足的时候停下然后考虑左边界右移&#xff0c;左边界只…

阿里5年经验之谈 —— 记录一次jmeter压测的过程!

在软件架构与中间件实验的最后&#xff0c;要求进行非功能测试&#xff0c;那得非压力测试莫属了。虽然之前学习秒杀项目的时候看视频里面用过jmeter&#xff0c;但没有自己实操过&#xff0c;趁着这次机会&#xff0c;使用一下。 QPS与TPS 1、TPS&#xff1a; Transactions …

matlab如何实现任意长序列所有排列方式

最近被问到一个问题&#xff0c;如何计算一个由3个0和3个1组成的序列的所有组合情况&#xff0c;处理这个问题我没有找到特别恰当的函数&#xff08;如果有能直接做的函数欢迎评论告知&#xff09;&#xff0c;所以采用比较接近需求的perms函数来解决这个问题 首先看perms函数…

小望电商通:无代码开发,轻松实现电商平台、客服系统和用户运营的集成

无缝连接电商系统和客服系统&#xff0c;轻松实现集成 小望电商通是一款具有突破性的电商解决方案。它为电商行业提供了新的可能性&#xff0c;尤其在电商系统和客服系统的无缝连接和集成上具有显著优势。小望电商通的运用&#xff0c;使企业无需进行任何API开发&#xff0c;就…

单区域OSPF配置

配置命令步骤&#xff1a; 1.使用router ospf 进程ID编号 启用OSPF路由 2.使用network 直连网络地址 反掩码 area 0 将其归于区域0 注意&#xff1a;1.进程ID编号可任意&#xff08;1-65535&#xff09;2.反掩码用4个255相减得到 如下图&#xff0c;根据给出要求配置OSPF单区…

IDEA插件推荐:Apipost-Helper

IDEA是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序。我们在编写完接口代码后需要进行接口调试等操作&#xff0c;一般需要打开额外的调试工具。 今天给大家介绍一款IDEA插件&#xff1a;Api…

LeetCode(20)最长公共前缀【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 14. 最长公共前缀 1.题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow&qu…

flutter TabBar指示器

第一层tabView import package:jade/configs/PathConfig.dart; import package:jade/customWidget/MyCustomIndicator.dart; importpackage:jade/homePage/promotion/promotionPost/MyPromotionListMainDesc.dart; import package:jade/homePage/promotion/promotionPost/MyPr…

CANoe-Trace窗口介绍

1、什么是Trace窗口 Trace窗口的目的是在测量期间(CANoe运行时)记录总线活动。在测试设置(Measurement Setup)中的Trace窗口的输入处接收到的所有消息都在Trace输出窗口中显示为文本。 当然,除了总线报文数据外,还有一系列的其他事件可以输出到Trace窗口,例如: 错误事…

【网络基础实战之路】基于不同协议间使用重发布路由策略

系列文章传送门&#xff1a; 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 【网络基础实战之路】基于…

香港优才计划获批概率跌破20%,拿香港身份越来越难了?

香港优才计划获批概率跌破20%&#xff0c;拿香港身份越来越难了&#xff1f; 截止10月31日&#xff0c;香港各类人才引进计划共收到18万4538宗申请&#xff0c;获批11万5741宗&#xff0c;整体“获批率”为62.72%。 具体到项目获批率&#xff1a; ①优才计划共收到63979宗申请&…

自动化测试介绍和分类,看这一篇就够了

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…