美文网首页
为什么不要用 StringBuffer 和 Vector

为什么不要用 StringBuffer 和 Vector

作者: Ethan_Walker | 来源:发表于2018-04-25 23:00 被阅读20次

    原文链接

    很多人在回答新手提问的时候会说,StringBuilder 是非同步的,所以快一些,StringBuffer是同步(线程安全)的,所以慢一些。

    从技术上说这句话是没有错的,但是为什么多线程的时候仍然用 StringBuilder,不建议用StringBuffer(StringBuffer 建议永远不要使用)?

    简单的说,StringBuffer的“线程安全”在大多数时候增加了大量不必要的成本,并且未必达到目的。
    看下面的代码:

    StringBuffer buffer = getStringBuffer();
    for(int i=0; i<10000; i++)   buffer.append(i); // append 方法上由关键字 synchronized ,是同步方法
    

    StringBuffer 的每一步操作都先获取同步锁,然后释放同步锁。
    所以这段代码中,它获取了10000次锁,释放了10000次锁。

    除了获取、释放10000次锁的高昂成本之外,它真的实现了“线程安全”的目的吗?
    假如在这个for循环运行的过程中,有另一个线程对 buffer 做了操作:

    buffer.append("some string");
    

    那么这个 "some string" 就会插入某两个数字之间!因为在任意两次 append 数字之间,有一个“释放锁”再“获取锁”的极短暂的间隔,这时候是可以被其他线程获取锁的。
    换句话说,StringBuffer 所提供的所谓“线程安全”,并不包括多个操作之间的“原子性”支持。

    要想前述的for循环不受干扰地完成,用户还是需要手动上锁:

    final StringBuffer buffer = getStringBuffer();
    synchronized(buffer) {
      for(int i=0; i<10000; i++)
            buffer.append(i);
    }
    

    这样是保证了在for循环运行期间不受其他线程干扰,可是如前所述,10000次锁值 +1 和 -1 的成本还是有的,并且这个成本变成了“完全没有必要”的无意义成本。
    这就是为什么 StringBuffer这个类天生缺陷。

    在API设计中有一条规则是这样说的:

    一个类不应该自己实现同步,而应该把同步的工作留给用户。

    在绝大多数情况下,把同步的工作留给应用代码,而不是工具类的代码。

    这是因为: 一个类的用户总是比它的设计者更清楚,什么时候应该同步,应该作什么样的同步,并且,在不同的环境下,用户可能对“如何同步”有不同的需求.

    因为同样的原因,Vector 也有这样的天生设计缺陷,java的设计者认识到这种缺陷,所以后来才有了 ArrayList 才有了 StringBuilder。

    不幸的是,在API的编写中有这样一种规则:任何公开的东西都已经被冻结,任何签名、接口、承诺、结构等等都不能再改动,因为公开就表示已经有大量的用户代码依赖于此。用户能看到的所有的东西他们都会去依赖,假如你做改动,就会有成千上万的用户代码不能再运行或不能再编译。
    所以这两个类还在哪里,但是不表示我们在新的代码里还要去用它们。

    最后总结:
    100%的情况下不要用 StringBuffer
    99% 的情况下不要用 Vector
    那么那剩下的 1% 用 Vector 的情况在哪呢?
    熟悉Swing的都知道: 现有的一些 model 的类里面用了 Vector,假如你去定制它们,有时不可避免要用到 Vector。

    相关文章

      网友评论

          本文标题:为什么不要用 StringBuffer 和 Vector

          本文链接:https://www.haomeiwen.com/subject/yieulftx.html