看String源码的疑惑

今天看JDKString源码有一段代码实在没想通,网上也没有什么资料,说说自己的理解。先贴上jdk这一段源码:

publicbooleancontentEquals(CharSequencecs){

//ArgumentisaStringBuffer,StringBuilder

if(csinstanceofAbstractStringBuilder){

if(csinstanceofStringBuffer){

synchronized(cs){

returnnonSyncContentEquals((AbstractStringBuilder)cs);

}

}else{

returnnonSyncContentEquals((AbstractStringBuilder)cs);

}

}

//ArgumentisaString

if(csinstanceofString){

returnequals(cs);

}

//ArgumentisagenericCharSequence

charv1[]=value;

intn=v1.length;

if(n!=cs.length()){

returnfalse;

}

for(inti=0;i<n;i++){

if(v1[i]!=cs.charAt(i)){

returnfalse;

}

}

returntrue;

}

这是一个比较char序列的方法,但是这个方法为什么判断是stringbuff要加同步关键字,而StringBuilder却不加同步关键字,不是说StringBuffer才是同步的吗?要加这一段应该都加上。想不通,死活想不通,然后百度只有知乎上有一段回答:

因为“StringBuffer是线程安全的”是个非常不准确的命题——不谈场景无从谈起线程安全与否。

事实上题主贴出来的代码正是JDK为了维护StringBuffer在此场景中的“线程安全”的表象而做的保护。

这里的重点是:这是JDK的内部实现,所以有意为了速度而破坏了封装。String.nonSyncContentEquals()方法直接把AbstractStringBuilder的value字段指向的char[]拿了出来读取其内容。如果此时这是一个StringBuffer,而另一个线程正在对该StringBuffer的内容做修改,那么此处不锁住该StringBuffer实例的话,这个value数组里的内容就可能会并发的发生变化,这个方法就不可靠了。

所以,为了补偿破坏了的封装,这里就代劳StringBuffer的线程安全性,给它加上了锁。

链接:https://www.zhihu.com/question/41922604/answer/92956253

读这段回答还是没有明白为什么stringbuild不加关键字。我就连续读了5遍这段话。。。终于有点眉目了,说说自己的想法:

严格意义上来说,这里其实可以都不加关键字,在调用这个方法的时候才加上同步关键字,这样就可以保证同步问题,同时效率会更高。但是源码这样写的原因,就是保证了stringbuffer的那句话,stringbuffer是线程安全的,调用这个方法的时候,给人一种假象,只要传入的是stringbuffer的话,就是安全的。所以实际上整个方法是牺牲了速度来保障StringBuffer的安全。