看String源码的疑惑

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

  public boolean contentEquals(CharSequence cs) {
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            if (cs instanceof StringBuffer) {
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }
        // Argument is a String
        if (cs instanceof String) {
            return equals(cs);
        }
        // Argument is a generic CharSequence
        char v1[] = value;
        int n = v1.length;
        if (n != cs.length()) {
            return false;
        }
        for (int i = 0; i < n; i++) {
            if (v1[i] != cs.charAt(i)) {
                return false;
            }
        }
        return true;
    }

这是一个比较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的安全。


猜你喜欢

转载自chen-sai-201607223902.iteye.com/blog/2332175