当前位置: 首页 > news >正文

Java基础:String、StringBuilder 和 StringBufferr对比

目录

基础用法

1.String

2.StringBuilder和StringBufferr

略微深入

1.为什么StringBuiler线程不安全

2.为什么StringBuffer线程安全


基础用法

1.String

在Java中,String是不可变类。

所以new一个String对象之后,它的值是不可变的。对它的修改,实际上是生成新对象。

例如:

public class StringExample { public static void main(String[] args) { String str1 = "Hello"; String str2 = str1.concat(", World!"); System.out.println(str1); // 输出:Hello System.out.println(str2); // 输出:Hello, World! } }

2.StringBuilder和StringBufferr

二者都是可变类,也就是能在不生成新对象的情况下修改字符串。单纯从使用角度来看是差不多的

例如:

public class StringBuilderExample { public static void main(String[] args) { StringBuilder sb = new StringBuilder("Hello"); sb.append(", World!"); System.out.println(sb.toString()); // 输出:Hello, World! } }

略微深入

三者之间的区别很直观,如下表所示。接下来主要基于具体问题,深入源码分析

1.为什么StringBuiler线程不安全

StringBuilder 和 StringBuffer,二者都继承父类 AbstractStringBuilder。

对象内部核心就两个成员:

char[] value; // 真正存放字符的数组 int count; // 记录数组里实际存了多少个有效字符

StringBuilder中的append,直接调用父类:

@Override public StringBuilder append(String str) { // 直接调用父类 AbstractStringBuilder 的append super.append(str); return this; }

再看父类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位置开始写入 count += len; // 计数器自增 return this; }

重点关注计数器自增操作,这也是导致线程不安全的原因:

问题 1:count += len 非原子操作
count += len 会拆分成 3 步 CPU 指令:
读取 count 当前值;
执行加法运算;
将结果写回 count 变量。
如果多线程同时执行:
线程 A、线程 B 读到同一个 count 值,加法完成后先后写回,后写入的值会覆盖前一个,最终 count 偏小,字符丢失。

问题 2:ensureCapacityInternal 并发判断产生越界
线程 A、线程 B 同时判断,都认为容量充足,不触发扩容。
此时线程 A先拼接,线程B后拼接,一起拼进去长度可能就超出数组范围了,会抛出 ArrayIndexOutOfBoundsException。

2.为什么StringBuffer线程安全

看StringBuffer的append方法:

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

好像和StringBuilder差不多?

关键点在于多了synchronized修饰:

synchronized是 Java 内置的悲观锁,JVM 层面实现,用来保证多线程并发下:
原子性:代码块一次性执行完毕,不会被线程打断
可见性:一个线程修改变量,其他线程立刻可见
有序性:禁止指令重排

自然也就不会出现和StringBuilder一样的问题,因为多个线程访问同一个对象的同一方法会互斥。

http://www.gsyq.cn/news/1591880.html

相关文章:

  • 告别复杂命令行:3步轻松掌握Android设备图形化管理
  • NL2SQL落地企业遇阻?语义映射与查询验证是破局关键
  • 从一次性 Prompt 到连续工作流:投研 Agent 为什么需要长期可用的数据入口?
  • 移动优先时代:本地GEO优化的移动端适配技巧
  • 算子代数视角:用谱复杂性解析Navier-Stokes方程与湍流本质
  • Java开发环境一键起飞(IDEA 2024最新版全栈配置手册)
  • 如何通过SMUDebugTool深度掌控AMD Ryzen处理器性能?
  • 代数几何中的特殊曲面:Coble曲面与Bertini对合探析
  • 智能业务代表员中的远程调用代理与服务定位
  • Selenium自动化测试最佳实践:从框架选型到CI/CD集成的完整指南
  • openYuanrong 多语言运行时:如何实现类单机编程的高性能分布式运行?[特殊字符]
  • 从 PHP 到 AI + Golang,程序员自救转型手记(七):建立 CLAUDE.md 文件、整理目录结构
  • 终极指南:如何免费快速安装大气层整合包系统
  • FastAPI+LangChain打造智能招聘系统-网易云课堂
  • 头油头痒夏天总反复?用藿香正气水洗个头,比控油洗发水管用
  • 如何彻底清理Windows“此电脑“中的顽固图标:MyComputerManager完整指南
  • 别再重装系统了!IntelliJ IDEA迁移/重装后秒恢复全部配置的3种军工级备份法(含自动化脚本)
  • snscrape+Hugging Face实现无API推文情感分析
  • 诡异!MLCC 储存后随机短路?这篇复盘帮你揪出隐形元凶
  • MySQL 8.4.9 部署
  • 3000万加注中医垂直大模型:ChatiSS 正在走一条 DeepSeek 式的「自造血」技术路线
  • 【通配符使用指南】
  • 基于HNN的化学家教统计计算平台的搭建
  • 全能电商3D立体促销标题字效样机
  • 【课程设计/毕业设计】消防知识数字化竞赛学习平台的设计与实现(SpringBoot) 社区消防安全教育竞赛小程序系统设计与实现【附源码、数据库、万字文档】
  • ScrapeGraphAI:用自然语言驱动的AI网页爬虫实战指南
  • 布格替尼(Brigatinib)不良反应,做好安全管控
  • 【计算机毕业设计案例】基于 SpringBoot 的书籍拍卖订单管理系统设计与实现 微信端图书拍卖交易运维管理系统设计与实现(程序+文档+讲解+定制)
  • VortMall微服务商城系统v1.3.7重磅更新|『邮箱登录+Facebook社交升级』
  • 太阳能板光伏缺陷检测数据集VOC+YOLO格式719张4类别