经常有关String,StringBuffer,StringBuilder之间比较的论调出现,结论通常是单线程情况下StringBuilder性能优于StringBuffer,但StringBuilder是线程不安全的,所以多线程并发编程时候要用StringBuffer。线程安全就是说多线程访问同一代码,不会产生不确定的结果。编写线程安全的代码是低靠线程同步。通常情况下,线程不安全的类效率高,速度更快 。那么,StringBuffer是如何保证线程安全的呢?
来吧,不道听途说,翻一翻源码。
* @author Arthur van Hoff
* @see java.lang.StringBuilder
* @see java.lang.String
* @since JDK1.0
*/
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
* @author Michael McCloskey
* @see java.lang.StringBuffer
* @see java.lang.String
* @since 1.5
*/
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
这里可见StringBuffer和StringBuilder来源出处是一致的,继承相同的类,实现相同的接口。这里可以看出StringBuffer从JDK1.0开始就有,StringBuilder从JDK1.5才出现。像大家所知道的那样,StringBuilder是为了提升StringBuffer效率而出现的。
StringBuffer的构造方法:
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
/**
* Constructs a string buffer with no characters in it and
* the specified initial capacity.
*
* @param capacity the initial capacity.
* @exception NegativeArraySizeException if the <code>capacity</code>
* argument is less than <code>0</code>.
*/
public StringBuffer(int capacity) {
super(capacity);
}
/**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
* <code>16</code> plus the length of the string argument.
*
* @param str the initial contents of the buffer.
* @exception NullPointerException if <code>str</code> is <code>null</code>
*/
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
/**
* Constructs a string buffer that contains the same characters
* as the specified <code>CharSequence</code>. The initial capacity of
* the string buffer is <code>16</code> plus the length of the
* <code>CharSequence</code> argument.
* <p>
* If the length of the specified <code>CharSequence</code> is
* less than or equal to zero, then an empty buffer of capacity
* <code>16</code> is returned.
*
* @param seq the sequence to copy.
* @exception NullPointerException if <code>seq</code> is <code>null</code>
* @since 1.5
*/
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
StringBuilder的构造方法:
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
/**
* Constructs a string builder with no characters in it and an
* initial capacity specified by the <code>capacity</code> argument.
*
* @param capacity the initial capacity.
* @throws NegativeArraySizeException if the <code>capacity</code>
* argument is less than <code>0</code>.
*/
public StringBuilder(int capacity) {
super(capacity);
}
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
* <code>16</code> plus the length of the string argument.
*
* @param str the initial contents of the buffer.
* @throws NullPointerException if <code>str</code> is <code>null</code>
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
/**
* Constructs a string builder that contains the same characters
* as the specified <code>CharSequence</code>. The initial capacity of
* the string builder is <code>16</code> plus the length of the
* <code>CharSequence</code> argument.
*
* @param seq the sequence to copy.
* @throws NullPointerException if <code>seq</code> is <code>null</code>
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
所有构造方法都一致。
public synchronized int length() {
return count;
}
public synchronized int capacity() {
return value.length;
}
public synchronized void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > value.length) {
expandCapacity(minimumCapacity);
}
}
StringBuilder没有重写length()和capacity()等方法,StringBuffer给方法添加了同步锁,从这里开始,StringBuffer和StringBuilder出现区别。StringBuffer把所有操作类的方法均添加同步锁,而StringBuilder并没有。
StringBuffer的append方法:
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
StringBuilder的append方法:
private StringBuilder append(StringBuilder sb) {
if (sb == null)
return append("null");
int len = sb.length();
int newcount = count + len;
if (newcount > value.length)
expandCapacity(newcount);
sb.getChars(0, len, value, count);
count = newcount;
return this;
}
这里append,作为StringBuffer/StringBuilder最常用的方法之一,区别已经很明显了。(这里也可以看到,StringBuffer的很多方法是在JDK1.5版本的时候才添加的)
查看synchronized的描述吧:
synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须 获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法 返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。
所以,StringBuffer不可避免的比StringBuilder慢。在不需要考虑线程安全的代码,尽量还是使用StringBuilder吧。顺便,HashTable和HashMap之间的关系也是这样的。HashTable源码里,也充斥着synchronized。