对于国内面试中经常问“StringBuffer和StringBuilder有何区别”,知乎上曾有一番讨论。
我以为,好的面试官可以在这个问题上直接进一步,“你不知道这两个的区别没关系,我可以告诉你,我们聊聊短生命周期对象管理和线程安全性吧。”所以取而代之的这样的一个问题就更有意义了:请写一个程序来验证StringBuffer和StringBuilder的线程安全性。
线程安全性是指,当对一个复杂对象进行某种操作时,从操作开始到操作结束之前,该对象会经历若干中间状态,直到操作完全结束,该对象才会会到完全可用的状态。如果其他线程能够访问处于不可用中间状态的对象,使该对象产生无法预料的结果,则称该对象线程不安全,反之则称其为线程安全。
所以这个简单程序的考察点:
- 线程安全性的理解
- Java并发编程基础
- 主动思考和分析能力,以及去求证的主动性,而不是被动接受各种结论
示例程序如下:
public class StringBufferAndStringBuilderTest { private static final int THREAD_NUM = 1000; public static void main(String[] args){ long startTime = System.currentTimeMillis(); String strToReverse = "AAAABBBB"; StringBuffer stringBuffer = new StringBuffer(strToReverse); StringBuilder stringBuilder = new StringBuilder(strToReverse); CountDownLatch countDownLatch = new CountDownLatch(THREAD_NUM); CountDownLatch countDownLatch2 = new CountDownLatch(THREAD_NUM); for(int i=0; i<THREAD_NUM; i++) { new StringBufferTaskThread(stringBuilder, countDownLatch).start(); new StringBufferTaskThread(stringBuffer, countDownLatch2).start(); } try { countDownLatch.await(); countDownLatch2.await(); System.out.println("StringBuffer toString: " + stringBuffer.toString()); System.out.println("StringBuilder toString: " + stringBuilder.toString()); long endTime = System.currentTimeMillis(); System.out.println("Running time: " + (endTime-startTime)); } catch (InterruptedException e) { e.printStackTrace(); } } } class StringBufferTaskThread extends Thread { private static final String STARTER = "-start"; private static final String ENDER = "-end"; private Object s = null; private CountDownLatch countDownLatch; // 记载运行线程数 public StringBufferTaskThread(StringBuilder stringBuilder, CountDownLatch countDownLatch) { super(); this.s = stringBuilder; this.countDownLatch = countDownLatch; } public StringBufferTaskThread(StringBuffer stringBuffer, CountDownLatch countDownLatch) { super(); this.s = stringBuffer; this.countDownLatch = countDownLatch; } @Override public void run() { System.out.println(Thread.currentThread().getName() + STARTER); for(int i=0; i<10; i++) { try { Thread.sleep(200); if(s instanceof StringBuffer){ ((StringBuffer) s).reverse(); System.out.println("Buffer->"+s.toString()); }else if(s instanceof StringBuilder){ ((StringBuilder) s).reverse(); System.out.println("Builder->"+s.toString()); } Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + ENDER); countDownLatch.countDown(); } }此示例程序做了如下事情:
- 基于初始字符串“AAAABBBB”分别构建StringBuffer和StringBuilder对象
- 分别启动1000个线程,调用StringBuffer和StringBuilder的reverse方法,进行字符串反转
- 所有线程执行完后打印结果,由于反转偶数次,线程安全的对象输出应与初始值相同,线程不安全的对象则可能产生乱序
输出:
Thread-0-start Thread-1-start Thread-2-start Thread-3-start Thread-4-start Thread-5-start Thread-6-start Thread-7-start .... Thread-368-end Thread-1809-end Thread-1609-end Thread-1810-end Thread-1608-end Thread-1702-end Thread-1527-end StringBuffer toString: AAAABBBB StringBuilder toString: ABBBBBAB Running time: 7523发现StringBuffer输出与初始值相同,StringBuilder输出产生乱序。多次执行或调大线程数StringBuffer输出结果不变,由此二者线程安全性得证。
相关推荐
这种情况就不再受`StringBuffer`的线程安全性保护。 例如,假设我们有三个线程A、B和C,每个线程都有自己的`StringBuffer`实例,然后它们都试图将结果附加到一个共享的`StringBuffer`实例。如果线程A完成了它的`...
- StringBuffer是线程安全的字符串操作类,适合在多线程环境中使用。 - 它提供了`append()`方法来添加字符或字符串,还有`insert()`插入指定位置,`delete()`和`replace()`修改已有内容,`reverse()`反转字符串等...
- `StringTest.java`, `StringTest2.java`, `StringTest3.java`, `StringTest4.java`可能是对字符串操作的进一步测试,以验证线程安全性和线程间通信的效果。 5. **线程同步机制**: - **管程(Monitor)**:Java...
它们的主要区别在于线程安全方面:StringBuffer是线程安全的,适合在多线程环境中使用;而StringBuilder没有同步机制,因此在单线程环境下,StringBuilder的性能通常优于StringBuffer。在《宝莱坞游戏》中,由于游戏...
在Java编程领域,安全性是至关重要的,特别是在开发大型企业级应用或者处理敏感用户数据时。这篇博客"Java安全性编程实例"可能深入探讨了如何在Java环境中实现安全编码实践,以防止潜在的安全漏洞和攻击。虽然具体的...
3. **单元测试**:`teststringbuffer`可能是一个测试类,使用JUnit或其他测试框架(如TestNG)来验证`StringBuffer`操作的正确性。测试通常包括各种边界条件,例如空字符串、大字符串、并发操作等。 4. **版本控制*...
这是因为StringBuilder的方法不是synchronized的,它不具备线程安全性。因此,当多个线程同时访问StringBuilder时,它可能会产生一些不可预测的结果。 但是,如果我们在StringBuilder的方法前加上synchronized...
然而,需要注意的是,`StringBuilder`不具备线程安全特性,因此在多线程环境下,应当使用其线程安全的姐妹类`StringBuffer`。 单元测试在这种情况下也扮演着重要角色。编写针对`String`和`StringBuilder`的单元测试...
而在多线程环境下,StringBuffer由于其方法上的synchronized关键字,保证了线程安全,可以防止数据的不一致性。 接下来讨论ArrayList和LinkedList,它们都是List接口的实现,但内部实现方式不同,因此在性能上有...
- **线程安全性**:`Hashtable`是线程安全的,而`HashMap`不是。 - **null值支持**:`HashMap`允许一个键和多个值为`null`,而`Hashtable`不允许任何键或值为`null`。 ##### 15. final、finally、finalize的区别 -...
**1.2 线程安全性** - **StringBuilder**:非线程安全,适用于单线程环境。 - **StringBuffer**:线程安全,适用于多线程环境。其内部方法通过`synchronized`关键字实现同步,确保了在多线程并发访问时数据的一致性...
- `StringBuilder`是单线程环境下的高效字符串操作类,它是`StringBuffer`的非线程安全版本。在单线程环境下,`StringBuilder`通常比`StringBuffer`更快,因为不需要考虑线程同步开销。 - 方法与`StringBuffer`...
2. String、StringBuffer、StringBuilder的区别:String是不可变对象,StringBuffer和StringBuilder是可变对象,StringBuffer是线程安全的,而StringBuilder不是。 3. int和Integer的区别:int是基本数据类型,...
- **StringBuilder**:非线程安全,性能较高。 - 在多线程环境下推荐使用 **StringBuffer**,而在单线程环境中建议使用 **StringBuilder** 以提高性能。 ### 5. int 与 Integer 的区别 #### 基本类型与包装类 - **...
- 从JDK 5开始引入,作为StringBuffer的非线程安全版本。 - 在单线程环境下,性能优于StringBuffer。 - 推荐在大多数情况下使用StringBuilder,除非确实需要线程安全的字符串操作。 #### 字符串分割函数 ```...
`StringBuffer`是线程安全的,适合多线程环境;`StringBuilder`非线程安全但速度更快。 4. **运行时异常与非运行时异常**: 运行时异常在程序运行时才会出现,如空指针异常、数组越界等,可以直接或通过try-catch...
6. **final关键字**:用于声明变量、方法或类为不可变,保证了数据的不可变性和多线程安全性。 7. **内存泄漏和内存溢出**:内存泄漏是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,导致系统内存...
`StringBuffer`中的方法如`append`被`synchronized`关键字修饰,确保同一时间只有一个线程能执行该方法,从而保证了线程安全性。 9. **互斥锁的概念**: 互斥锁是一种同步机制,用于确保同一时间只有一个线程能...
`StringBuilder`和`StringBuffer`都用于字符串拼接,但`StringBuffer`是线程安全的,适合多线程环境。它们的效率高于`String`,因为可以在原对象上修改。 - 抽象类与接口:抽象类用`abstract`关键字定义,可以包含...
1. **Java语言特点**:包括跨平台性、面向对象、自动内存管理、丰富的类库、健壮性和安全性等。 2. **面向对象与面向过程**:面向对象编程注重对象和类的抽象,而面向过程编程关注步骤和函数。 3. **数据类型**:...