StringBuffer与StringBuilder在jvm层次上的简谈

StringBuilder和StringBuffer的区别作为一个在java面试里面老生常谈的问题,一般的区别知道是因为一个做了同步一个没做,导致在单线程和线程安全的情况下StringBuffer会比StringBuilder效率差,但是到底具体底层是什么原因呢?我在这里做一个简单探讨。


首先看代码:

StringBuffer:


StringBuffer在每次append的时候都需要进行一个synchronized的消耗

StringBuilder:


StringBuilder不需要,所以StringBuilder在单线程和线程安全情况下性能会更好


下面我们再测试一下StringBuilder和StringBuffer在进行append花费的时间



appendTimes为50次:



appendTimes为


可以看出来buffer耗费时间是builder的4倍以上


那么问题来了,synchronized究竟做了什么导致stringBuffer和stringBuilder在性能上有如此大的差异呢?


由于本次是讨论单线程情况下,所以一下讨论均基于单线程情况下

首先明确下对象监控器(synchronized)的几种状态:

Contention List:所有请求锁的线程将被首先放置到该竞争队列

Entry List:Contention List中那些有资格成为候选人的线程被移到Entry List

Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set

OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck

Owner:获得锁的线程称为Owner

!Owner:释放锁的线程

下图转换状态:



每个线程首先会被放进contentionList里面(采取一个后进先出的机制,类似于栈),当某个owner线程执行unlock的时候,如果entryList为空,则会从contentionList里面去拿取一个线程放进去,并且知道你个entryList里面(一般是第一个)作为一个ready线程放进去onDeck(一般只有一个),然后释放锁让onDeck去竞争


这里原本说onDeck需要竞争,这是为什么呢?

原因是jvm会有一个优化,线程在进入contentionList之前会有一个自旋时间,大概是一个线程上下文切换的时间,如果在这个时间有锁释放出来,正在自选的线程就可以和onDeck的线程进行竞争锁


所以在单线程情况下,线程直接进入自旋,发现有锁之后直接获取,在次数较小的访问里面这个是可以忽略的,但是当append次数增多的时候,每次进入之前从自旋状态到获取锁到达owner状态这个期间的消耗就会非常的影响性能



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值