2015我想和Java聊聊之StringBuffer是如何保证线程安全的

经常有关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。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值