StringBuilder与StringBuffer

StringBuilder

  1. package com.keytech.task;
  2. import java.util.concurrent.CountDownLatch;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Semaphore;
  6. //线程不安全
  7. public class StringExample1 {
  8. public static Integer clientTotal=5000;
  9. public static Integer threadTotal=200;
  10. public static StringBuilder stringBuilder=new StringBuilder();
  11. public static void main(String[] args) throws Exception{
  12. ExecutorService executorService = Executors.newCachedThreadPool();
  13. final Semaphore semaphore=new Semaphore(threadTotal);
  14. final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);
  15. for (int i = 0; i < clientTotal; i++) {
  16. executorService.execute(()->{
  17. try{
  18. semaphore.acquire();
  19. update();
  20. semaphore.release();
  21. }catch (Exception e){
  22. e.printStackTrace();
  23. }
  24. countDownLatch.countDown();
  25. });
  26. }
  27. countDownLatch.await();
  28. executorService.shutdown();
  29. System.out.println("size"+stringBuilder.length());
  30. }
  31. private static void update() {
  32. stringBuilder.append("1");
  33. }
  34. }
  35. //size:4999

main函数中输出的结果不为预期的5000,并且每次结果可能会不一致,因此StringBuilder是线程不安全类

StringBuffer

  1. package com.keytech.task;
  2. import java.util.concurrent.CountDownLatch;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Semaphore;
  6. //线程安全
  7. public class StringExample2 {
  8. public static Integer clientTotal=5000;
  9. public static Integer threadTotal=200;
  10. public static StringBuffer stringBuffer=new StringBuffer();
  11. public static void main(String[] args) throws Exception{
  12. ExecutorService executorService = Executors.newCachedThreadPool();
  13. final Semaphore semaphore=new Semaphore(threadTotal);
  14. final CountDownLatch countDownLatch=new CountDownLatch(threadTotal);
  15. for (int i = 0; i < clientTotal; i++) {
  16. executorService.execute(()->{
  17. try{
  18. semaphore.acquire();
  19. update();
  20. semaphore.release();
  21. }catch (Exception e){
  22. e.printStackTrace();
  23. }
  24. countDownLatch.countDown();
  25. });
  26. }
  27. countDownLatch.await();
  28. executorService.shutdown();
  29. System.out.println("size:"+stringBuffer.length());
  30. }
  31. private static void update() {
  32. stringBuffer.append("1");
  33. }
  34. }
  35. //size:5000

StringBuffer每次输出的结果与预期结果一致,因此它是线程安全的类

StringBuffer使用synchronized保证线程安全

  1. @Override
  2. public synchronized StringBuffer append(String str) {
  3. toStringCache = null;
  4. super.append(str);
  5. return this;
  6. }

总结

通过以上两个例子可以知道,StringBuffer为线程安全类,StringBuilder为线程不安全类。

StringBuffer在方法的实现上使用了synchronized关键字对方法进行同步,因此是线程安全的,而StringBuilder则没有进行特殊的同步或并发处理。

StringBuffer使用了同步锁,同一时间只能有一个线程进行访问,因为在系统性能会有损耗,适用于多线程环境下使用。通常情况下,字符串拼接出现在方法内(在方法中以局部变量的方式使用,可以做到线程封闭),使用StringBuilder进行字符串的拼接会大大提高性能,属于堆栈封闭,单个线程的操作对象,因此不存在线程不安全问题,优先选择使用StringBuilder。两种字符串拼接类分别适用不同的场景,这就是为什么JAVA同时提供了这两种类。

返回笔记列表
入门小站