Answers:
StringBuffer
是同步的,StringBuilder
不是。
StringBuilder
比StringBuffer
因为不是更快synchronized
。
这是一个简单的基准测试:
public class Main {
public static void main(String[] args) {
int N = 77777777;
long t;
{
StringBuffer sb = new StringBuffer();
t = System.currentTimeMillis();
for (int i = N; i --> 0 ;) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
{
StringBuilder sb = new StringBuilder();
t = System.currentTimeMillis();
for (int i = N; i > 0 ; i--) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
}
}
一个试运行给出的数字2241 ms
为StringBuffer
VS 753 ms
的StringBuilder
。
--> 0
循环。花了我一点时间来了解它的含义。这是实际上在实践中使用的东西,而不是通常的...; i > 0; i--
语法吗?
i -->
语法角度看,这确实很烦人。由于有关ASCII艺术的评论,我起初以为是一个箭头。
main()
的基准测试。此外,您的基准测试也不公平。没有热身。
基本上,StringBuffer
方法是同步的,而StringBuilder
不是。
这些操作“几乎”相同,但是在单个线程中使用同步方法是过大的。
差不多了。
此类[StringBuilder]提供与StringBuffer兼容的API,但不保证同步。此类设计为在单线程正在使用字符串缓冲区的地方(通常是这种情况)来代替StringBuffer。在可能的情况下,建议优先使用此类而不是StringBuffer,因为在大多数实现中它会更快。
因此它被替代了。
同样的事情发生Vector
和ArrayList
。
Hashtable
和HashMap
。
但是需要借助示例来获得明显的不同吗?
StringBuffer或StringBuilder
StringBuilder
除非您确实试图在线程之间共享缓冲区,否则请简单使用。StringBuilder
是原始同步StringBuffer
类的未同步(开销较小=更有效)的弟弟。
StringBuffer
首先。Sun在所有情况下都关注正确性,因此他们将其同步以使其具有线程安全性,以防万一。
StringBuilder
以后再来 大多数的使用StringBuffer
都是单线程的,不必要地支付了同步的费用。
由于StringBuilder
是直接替代的StringBuffer
不同步时,就不会有任何的例子之间的差异。
如果您在线程之间试图分享,你可以使用StringBuffer
,但考虑更高级别的同步是否是必要的,例如,也许不是使用StringBuffer的问题,您应该同步的是使用StringBuilder方法。
首先让我们看一下相似之处:StringBuilder和StringBuffer都是可变的。这意味着您可以在同一位置更改它们的内容。
区别:StringBuffer是可变的,并且也是同步的。其中StringBuilder是可变的,但默认情况下不同步。
同步(synchronization)的含义:当某事物同步时,多个线程可以访问并对其进行修改,而不会出现任何问题或副作用。StringBuffer是同步的,因此您可以将其与多个线程一起使用而不会出现任何问题。
何时使用哪一个? StringBuilder:当您需要一个可以修改的字符串时,只有一个线程正在访问和修改它。StringBuffer:当您需要一个可以修改的字符串,并且有多个线程正在访问和修改它时。
注意:不要不必要地使用StringBuffer,即,如果只有一个线程正在修改和访问它,则不要使用它,因为它具有大量用于同步的锁定和解锁代码,这将不必要地占用CPU时间。除非需要,否则不要使用锁。
在单线程中,由于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!
因此,Builder比Buffers快,而WAY比字符串连接快。现在,我们将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 ms相比,您可以放心地假设StringBuffers追加在使用multithreading时较慢。其原因是,在JIT /热点/编译器/东西使得优化,当它检测到有没有必要检查锁。
但是,使用StringBuilder可以使用java.lang.ArrayIndexOutOfBoundsException,因为并发线程会尝试在不应添加的位置添加内容。
结论是您不必追求StringBuffers。在有线程的地方,请先考虑一下它们在做什么,然后再尝试增加几纳秒的时间。
withString+="some string"+i+" ; ";
并不等效于其他两个循环,因此不是公平的比较。
StringBuilder是Java 1.5中引入的,因此它不适用于早期的JVM。
从Javadocs:
StringBuilder类提供与StringBuffer兼容的API,但不保证同步。此类设计为在单线程正在使用字符串缓冲区的地方(通常是这种情况)来代替StringBuffer。在可能的情况下,建议优先使用此类而不是StringBuffer,因为在大多数实现中它会更快。
StringBuilder
。
很好的问题
我注意到这是差异:
StringBuffer:-
StringBuffer is synchronized
StringBuffer is thread-safe
StringBuffer is slow (try to write a sample program and execute it, it will take more time than StringBuilder)
StringBuilder:-
StringBuilder is not synchronized
StringBuilder is not thread-safe
StringBuilder performance is better than StringBuffer.
普通事:-
两者的签名方法相同。两者都是可变的。
字符串缓冲区
StringBuffer是可变的,意味着可以更改对象的值。通过StringBuffer创建的对象存储在堆中。StringBuffer与StringBuilder具有相同的方法,但是StringBuffer中的每个方法都是同步的,因为StringBuffer是线程安全的。
因此,它不允许两个线程同时访问同一方法。每种方法一次只能由一个线程访问。
但是,由于线程安全属性会导致StringBuffer的性能下降,因此线程安全也是不利的。因此,在调用每个类的相同方法时,StringBuilder比StringBuffer快。
可以更改StringBuffer的值,这意味着可以将其分配给新值。如今,这是一个最常见的面试问题,即上述课程之间的差异。可以使用toString()方法将字符串缓冲区转换为字符串。
StringBuffer demo1 = new StringBuffer(“Hello”) ;
// The above object stored in heap and its value can be changed .
demo1=new StringBuffer(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuffer
StringBuilder
StringBuilder与StringBuffer相同,即它将对象存储在堆中,也可以对其进行修改。StringBuffer和StringBuilder之间的主要区别是StringBuilder也不是线程安全的。StringBuilder速度很快,因为它不是线程安全的。
StringBuilder demo2= new StringBuilder(“Hello”);
// The above object too is stored in the heap and its value can be modified
demo2=new StringBuilder(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuilder
StringBuilder
(在Java 5中引入)与相同StringBuffer
,但其方法不同步。这意味着它比后者具有更好的性能,但是缺点是它不是线程安全的。
阅读教程以获取更多详细信息。
一个简单的程序,说明StringBuffer和StringBuilder之间的区别:
/**
* Run this program a couple of times. We see that the StringBuilder does not
* give us reliable results because its methods are not thread-safe as compared
* to StringBuffer.
*
* For example, the single append in StringBuffer is thread-safe, i.e.
* only one thread can call append() at any time and would finish writing
* back to memory one at a time. In contrast, the append() in the StringBuilder
* class can be called concurrently by many threads, so the final size of the
* StringBuilder is sometimes less than expected.
*
*/
public class StringBufferVSStringBuilder {
public static void main(String[] args) throws InterruptedException {
int n = 10;
//*************************String Builder Test*******************************//
StringBuilder sb = new StringBuilder();
StringBuilderTest[] builderThreads = new StringBuilderTest[n];
for (int i = 0; i < n; i++) {
builderThreads[i] = new StringBuilderTest(sb);
}
for (int i = 0; i < n; i++) {
builderThreads[i].start();
}
for (int i = 0; i < n; i++) {
builderThreads[i].join();
}
System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());
//*************************String Buffer Test*******************************//
StringBuffer sb2 = new StringBuffer();
StringBufferTest[] bufferThreads = new StringBufferTest[n];
for (int i = 0; i < n; i++) {
bufferThreads[i] = new StringBufferTest(sb2);
}
for (int i = 0; i < n; i++) {
bufferThreads[i].start();
}
for (int i = 0; i < n; i++) {
bufferThreads[i].join();
}
System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());
}
}
// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {
StringBuilder sb;
public StringBuilderTest (StringBuilder sb) {
this.sb = sb;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb.append("A");
}
}
}
//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {
StringBuffer sb2;
public StringBufferTest (StringBuffer sb2) {
this.sb2 = sb2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb2.append("A");
}
}
}
StringBuffer用于存储将要更改的字符串(无法更改String对象)。它会根据需要自动扩展。相关类:字符串,CharSequence。
StringBuilder是在Java 5中添加的。它在所有方面与StringBuffer相同,除了它不同步之外,这意味着如果多个线程同时访问它,可能会遇到麻烦。对于单线程程序,在最常见的情况下,避免同步的开销会使StringBuilder的速度稍快一些。
StringBuilder
通常是方法本地的,在方法中它们仅对一个线程可见。
StringBuffer 是可变的。它的长度和内容可以更改。StringBuffer是线程安全的,这意味着它们具有同步方法来控制访问,因此一次只有一个线程可以访问StringBuffer对象的同步代码。因此,在多个线程可能试图同时访问同一StringBuffer对象的多线程环境中,StringBuffer对象通常是安全的。
StringBuilder StringBuilder类与StringBuffer非常相似,不同之处在于其访问不同步,因此它不是线程安全的。通过不同步,StringBuilder的性能可以比StringBuffer更好。因此,如果您在单线程环境中工作,则使用StringBuilder代替StringBuffer可能会提高性能。在诸如StringBuilder局部变量(即方法中的变量)之类的其他情况下也是如此,其中只有一个线程将访问StringBuilder对象。
StringBuffer:
StringBuilder
String c = a + b
等于String c = new StringBuilder().append(a).append(b).toString()
,所以它不会更快。您创建的每串分配一个新的,而你可能只有一个这是唯一的(String d = a + b; d = d + c;
是String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();
同时StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();
将节省一个StringBuilder的instanciation)。
字符串构建器:
int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.
字符串缓冲区
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
建议尽可能使用StringBuilder,因为它比StringBuffer快。但是,如果必须保证线程安全,则最好的选择是StringBuffer对象。
更好地使用,StringBuilder
因为它不同步,因此提供了更好的性能。StringBuilder
是较早版本的直接替代StringBuffer
。
StringBu(ff|ild)er
是仅由单个线程使用的局部变量。
由于StringBuffer
已同步,因此需要一些额外的精力,因此基于性能,它比慢一点StringBuilder
。
A String
是一个不变的对象,这意味着该值StringBuffer
是可变的而不能更改。
的StringBuffer
同步,因此线程安全而StringBuilder
不是与适于仅单线程实例。
主要的区别是StringBuffer
同步化的,但是不是同步化StringBuilder
的。如果需要使用多个线程,则建议使用StringBuffer。但是,由于执行速度StringBuilder
比StringBuffer
它快,因为它没有同步化。
检查的同步追加方法StringBuffer
和的非同步追加方法的内部StringBuilder
。
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
由于append是synchronized
,StringBuffer
因此与StrinbBuilder
多线程方案相比具有性能开销。只要您不在多个线程之间共享缓冲区,请使用StringBuilder
,由于没有synchronized
in append方法,因此使用起来很快。
这是String vs StringBuffer vs StringBuilder的性能测试结果。最终,StringBuilder赢得了测试。请参阅下面的测试代码和结果。
代码:
private static void performanceTestStringVsStringbuffereVsStringBuilder() {
// String vs StringBiffer vs StringBuilder performance Test
int loop = 100000;
long start = 0;
// String
String str = null;
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
str += i + "test";
}
System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");
// String buffer
StringBuffer sbuffer = new StringBuffer();
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Buffer - " + (System.currentTimeMillis() - start) + " ms");
// String builder
start = System.currentTimeMillis();
StringBuilder sbuilder = new StringBuilder();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Builder - " + (System.currentTimeMillis() - start) + " ms");
}
结果:
100000次迭代以添加单个文本
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
10000次迭代以添加单个文本
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms