看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的安全。