浅谈 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:浅谈 SimpleDateFormat,第三方库joda-time,JDK8提供时间类 之性能和线程安全
下一篇:IDEA 查看类的继承结构与关系图

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月09日 12时44分11秒