StringBuffer和StringBuilder之间的主要区别是什么?在决定其中任何一项时是否存在性能问题?
当前回答
在单线程中,由于JVM的优化,StringBuffer不会比StringBuilder慢很多。在多线程中,不能安全地使用StringBuilder。
这是我的测试(不是基准测试,只是测试):
public static void main(String[] args) {
String withString ="";
long t0 = System.currentTimeMillis();
for (int i = 0 ; i < 100000; i++){
withString+="some string";
}
System.out.println("strings:" + (System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuffer buf = new StringBuffer();
for (int i = 0 ; i < 100000; i++){
buf.append("some string");
}
System.out.println("Buffers : "+(System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuilder building = new StringBuilder();
for (int i = 0 ; i < 100000; i++){
building.append("some string");
}
System.out.println("Builder : "+(System.currentTimeMillis() - t0));
}
结果:字符串:319740缓冲区:23建设者:7!
因此,构建器比缓冲区更快,比字符串串联更快。现在让我们为多个线程使用Executor:
public class StringsPerf {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
//With Buffer
StringBuffer buffer = new StringBuffer();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(buffer));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Buffer : "+ AppendableRunnable.time);
//With Builder
AppendableRunnable.time = 0;
executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(builder));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Builder: "+ AppendableRunnable.time);
}
static void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // code reduced from Official Javadoc for Executors
try {
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (Exception e) {}
}
}
class AppendableRunnable<T extends Appendable> implements Runnable {
static long time = 0;
T appendable;
public AppendableRunnable(T appendable){
this.appendable = appendable;
}
@Override
public void run(){
long t0 = System.currentTimeMillis();
for (int j = 0 ; j < 10000 ; j++){
try {
appendable.append("some string");
} catch (IOException e) {}
}
time+=(System.currentTimeMillis() - t0);
}
}
现在StringBuffers需要157毫秒才能完成100000次追加。这不是同一个测试,但与之前的37毫秒相比,您可以放心地假设,使用多线程时,StringBuffers追加的速度较慢。原因是JIT/hotspot/compiler/something在检测到不需要检查锁时会进行优化。
但是对于StringBuilder,您有java.lang.ArrayIndexOutOfBoundsException,因为并发线程试图在不应该添加的地方添加一些内容。
结论是,您不必追逐StringBuffers。如果您有线程,在尝试获得几纳秒之前,请考虑它们正在做什么。
其他回答
但需要借助一个例子来明确区别吗?StringBuffer或StringBuilder
只需使用StringBuilder,除非您确实试图在线程之间共享缓冲区。StringBuilder是原始同步StringBuffer类的非同步(开销更少=效率更高)弟弟。
StringBuffer排名第一。Sun关注所有条件下的正确性,因此他们使其同步,以使其线程安全,以防万一。
StringBuilder后来出现了。StringBuffer的大多数使用都是单线程的,不必要地支付了同步的成本。
由于StringBuilder是没有同步的StringBuffer的替代品,因此任何示例之间都不会有差异。
如果您试图在线程之间共享,可以使用StringBuffer,但要考虑是否需要更高级别的同步,例如,如果您同步使用StringBuilder的方法,可能不需要使用StringBuffer。
基本上,StringBuffer方法是同步的,而StringBuilder不是。
这些操作“几乎”相同,但在单个线程中使用同步方法是过度的。
这差不多了。
StringBuilder API报价:
此类[StringBuilder]提供了与StringBuffer兼容的API,但不保证同步。该类被设计为在单个线程使用字符串缓冲区的地方(通常情况下)作为StringBuffer的替代品。在可能的情况下,建议优先使用该类而不是StringBuffer,因为在大多数实现中,它会更快。
所以它是用来替代它的。
Vector和ArrayList也是如此。
字符串缓冲区是可变的。它可以在长度和内容方面改变。StringBuffers是线程安全的,这意味着它们有同步的方法来控制访问,这样一次只有一个线程可以访问StringBuffer对象的同步代码。因此,StringBuffer对象在多线程环境中使用通常是安全的,因为多个线程可能同时尝试访问同一StringBuffer。
字符串拼接StringBuilder类与StringBuffer非常相似,只是它的访问不同步,因此不是线程安全的。通过不同步,StringBuilder的性能可以优于StringBuffer。因此,如果您在单线程环境中工作,使用StringBuilder而不是StringBuffer可能会提高性能。这也适用于其他情况,例如StringBuilder局部变量(即方法中的变量),其中只有一个线程将访问StringBuilder对象。
StringBuffer中的每个方法都是同步的。因此,一次只允许一个线程操作StringBuffer对象。它增加了线程的等待时间并造成性能问题为了解决这个问题,SUN People推出了1.5版本的StringBuilder。
首先让我们看看相似之处:StringBuilder和StringBuffer都是可变的。这意味着您可以在同一位置更改它们的内容。
差异:StringBuffer也是可变的和同步的。其中,作为StringBuilder是可变的,但默认情况下不同步。
同步(synchronization)的含义:当某些东西被同步时,多个线程可以访问并修改它,而不会产生任何问题或副作用。StringBuffer是同步的,因此您可以在多个线程中使用它,而不会出现任何问题。
何时使用哪一个?StringBuilder:当您需要一个可以修改的字符串,并且只有一个线程在访问和修改它时。StringBuffer:当您需要一个可以修改的字符串,并且多个线程正在访问和修改它时。
注意:不要不必要地使用StringBuffer,也就是说,如果只有一个线程在修改和访问它,就不要使用它,因为它有很多用于同步的锁定和解锁代码,这将不必要地占用CPU时间。除非需要,否则不要使用锁。
推荐文章
- Java 8接口方法中不允许“同步”的原因是什么?
- 如何找到Java堆大小和内存使用(Linux)?
- 使用Enum实现单例(Java)
- RabbitMQ与通道和连接之间的关系
- buildSessionFactory()配置方法在Hibernate中已弃用?
- Spring MVC -如何获得所有的请求参数在一个地图在Spring控制器?
- 如何在Java中按两个字段排序?
- 文件之间的差异。路径中的分隔符和斜杠
- 在方法参数中使用NotNull注释
- Spring MVC中处理可选参数的@RequestParam
- Tomcat:如何查找正在运行的Tomcat版本?
- “java”、“javaw”和“javaws”之间有什么区别?
- 将Date对象转换为日历对象
- 在Java中保存最后N个元素的大小有限的队列
- 如何运行一个类从Jar不是主类在其清单文件