浅谈 String StringBuilder StringBuffer 之性能和线程安全
发布日期:2021-06-30 12:37:17
浏览次数:3
分类:技术文章
本文共 5639 字,大约阅读时间需要 18 分钟。
文章目录
一、String 字符串常量
String 是
不可变对象
,每次对 String 对象进行改变都会生成一个新的 String 对象,然后将指针指向新的 String 对象,故经常改变内容的字符串最好不要用 String 。因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度就更加慢了。
package com.nobody.part01;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;/** * @author Mr.nobody * @Description 测试String字符串拼接性能 * @date 2020/9/17 */public class StringDemo { // 请求总数 private static int CLIENT_COUNT = 10000; // 并发线程数 private static int THREAD_COUNT = 500; // 全局变量 private static String STRING = new String(); public static void main(String[] args) throws InterruptedException { // 固定线程池 ExecutorService executorService = Executors.newFixedThreadPool(CLIENT_COUNT); // 控制同一个时刻,只能有多少个线程同时运行指定代码,即acquire和release之间的代码 Semaphore semaphore = new Semaphore(THREAD_COUNT); CountDownLatch countDownLatch = new CountDownLatch(CLIENT_COUNT); long startTime = System.currentTimeMillis(); for (int i = 0; i < CLIENT_COUNT; i++) { executorService.execute(() -> { try { semaphore.acquire(); STRING += "0"; semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } finally { countDownLatch.countDown(); } }); } // 等待所有请求执行完 countDownLatch.await(); // 关闭线程池 executorService.shutdown(); long endTime = System.currentTimeMillis(); System.out.println("String -- 总共耗时:" + (endTime - startTime) + "ms,字符串长度:" + STRING.length()); }}
二、StringBuffer 字符串变量
StringBuffer 是
可变对象
,每次对 StringBuffer 对象进行改变都会对StringBuffer 对象本身进行操作。而不是生成新的对象,再改变对象引用。如果 StringBuffer 对象在多线程环境下,特别是字符串对象经常改变的情况下,推荐使用它 。因为 StringBuffer 几乎所有的方法都加了synchronized关键字,所以是线程安全的,但是性能会相对较差。
package com.nobody.part01;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;/** * @author Mr.nobody * @Description 测试线程安全类StringBuffer * @date 2020/9/17 */public class StringBufferDemo { // 请求总数 private static int CLIENT_COUNT = 10000; // 并发线程数 private static int THREAD_COUNT = 500; // 全局变量,线程安全StringBuffer private static StringBuffer STRINGBUFFER = new StringBuffer(); public static void main(String[] args) throws InterruptedException { // 固定线程池 ExecutorService executorService = Executors.newFixedThreadPool(CLIENT_COUNT); // 控制同一个时刻,只能有多少个线程同时运行指定代码,即acquire和release之间的代码 Semaphore semaphore = new Semaphore(THREAD_COUNT); CountDownLatch countDownLatch = new CountDownLatch(CLIENT_COUNT); long startTime = System.currentTimeMillis(); for (int i = 0; i < CLIENT_COUNT; i++) { executorService.execute(() -> { try { semaphore.acquire(); STRINGBUFFER.append("0"); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } finally { countDownLatch.countDown(); } }); } // 等待所有请求执行完 countDownLatch.await(); // 关闭线程池 executorService.shutdown(); long endTime = System.currentTimeMillis(); System.out.println("StringBuffer -- 总共耗时:" + (endTime - startTime) + "ms,字符串长度:" + STRINGBUFFER.length()); }}
三、StringBuilder 字符串变量
StringBuilder 一个
可变的字符序列
。StringBuilder 提供一个与 StringBuffer 兼容的 API,但不保证同步(即线程不安全
)。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)
。在堆栈封闭等线程安全的环境下(方法中的局部变量)应该首选 StringBuilder。
package com.nobody.part01;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;/** * @author Mr.nobody * @Description 测试线程不安全类StringBuilder * @date 2020/9/17 */public class StringBuilderDemo { // 请求总数 private static int CLIENT_COUNT = 10000; // 并发线程数 private static int THREAD_COUNT = 500; // 全局变量,线程不安全StringBuilder private static StringBuilder STRINGBUILDER = new StringBuilder(); public static void main(String[] args) throws InterruptedException { // 固定线程池 ExecutorService executorService = Executors.newFixedThreadPool(CLIENT_COUNT); // 控制同一个时刻,只能有多少个线程同时运行指定代码,即acquire和release之间的代码 Semaphore semaphore = new Semaphore(THREAD_COUNT); CountDownLatch countDownLatch = new CountDownLatch(CLIENT_COUNT); long startTime = System.currentTimeMillis(); for (int i = 0; i < CLIENT_COUNT; i++) { executorService.execute(() -> { try { semaphore.acquire(); STRINGBUILDER.append("0"); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } finally { countDownLatch.countDown(); } }); } // 等待所有请求执行完 countDownLatch.await(); // 关闭线程池 executorService.shutdown(); long endTime = System.currentTimeMillis(); System.out.println("StringBuilder -- 总共耗时:" + (endTime - startTime) + "ms,字符串长度:" + STRINGBUILDER.length()); }}
四、总结
- 对于不可变字符串或者字符串内容改变少的情况,推荐 String。
- 字符串对象可能会被多线程访问,并且经常改变内容,推荐 StringBuffer。
- 在堆栈封闭等线程安全的环境下(方法中的局部变量)推荐 StringBuilder。
转载地址:https://javalib.blog.csdn.net/article/details/108654332 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2024年04月09日 12时44分11秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
私钥加密
2019-05-01
私钥加密私钥解密
2019-05-01
私钥加密公钥解密
2019-05-01
获取私钥key对象
2019-05-01
获取公钥对象
2019-05-01
什么是数字签名
2019-05-01
数字签名原理
2019-05-01
锁的释放流程-ReentrantLock.unlock
2019-05-01
锁的释放流程-ReentrantLock.tryRelease
2019-05-01
锁的释放流程-unparkSuccessor
2019-05-01
ConcurrentHashMap的源码分析-tryPresize
2019-05-01
生产者消费者的实际使用
2019-05-01
阻塞队列的使用案例-注册成功后增加积分
2019-05-01
序列化的高阶认识-Transient 关键字
2019-05-01
序列化的高阶认识-绕开 transient 机制的办法
2019-05-01
Java 序列化的一些简 单总结
2019-05-01
分布式架构下常见序列化技术-了解序列化的发展
2019-05-01
Java判断字符串是否为数字(浮点类型也包括)
2019-05-01
DNS服务各功能实现方法
2019-05-01
Nginx服务各功能实现方法
2019-05-01