`

看String源码的疑惑

    博客分类:
  • java
阅读更多
今天看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的安全。


分享到:
评论

相关推荐

    Java中的String为什么是不可变的?? String源码分析

    什么是不可变对象?  众所周知, 在Java中, String类是不可变的...  对于Java初学者, 对于String是不可变对象总是存有疑惑。看下面代码:  String s = "ABCabc";  System.out.println("s = " + s);  s = "1

    new String(\"abc\")创建几个对象的解释

    java面试的疑惑剪辑 博文链接:https://z-jq1015.iteye.com/blog/248599

    C#操作注册表源码--适合初学者参考

    在IT领域,尤其是在软件开发中,C#是一种广泛使用的编程语言,尤其在Windows平台上。...社区、论坛、博客以及在线教程都能提供大量资源,帮助初学者解决疑惑。祝你在C#和注册表操作的学习旅程中取得成功!

    Android学习下 toast notification用法.rar

    这个方法需要三个参数:上下文(Context)、要显示的消息文本(String)和持续时间(int)。持续时间可以是`LENGTH_SHORT`或`LENGTH_LONG`,分别代表短时间和长时间显示。 ```java Toast.makeText(context, "Hello, ...

    Android仿engadget菜单特效源代码

    摘要:Java源码,Android源码,Android菜单 Android模仿的engadget TabBar菜单效果,有一个疑惑,咋实现当tab点击后,换一个Icon图呢?跟engadget的一样。  public void onTabChanged(String tabId)里无法实现,如果...

    Android 模仿engadget 点击切换图片的TAB菜单.rar

    Android TAB菜单,仿engadget导航切换菜单效果,其实就是一个TAB,这个相信大家都比较熟悉了,在电脑上和Android、IOS系统中都很常见。。...在public void onTabChanged(String tabId)里无法实现。

    编辑框文本循环滚动-易语言

    这通常涉及到计时器(Timer)组件和字符串处理(String Handling)技术。 1. **创建编辑框和计时器对象**: 在易语言的界面上,首先需要添加一个编辑框组件和一个计时器组件。编辑框用于显示文本,计时器则用来...

    大名鼎鼎SWFUpload- Flash+JS 上传

     name : string, // The file name. The path is not included.  size : number, // The file size in bytes  type : string, // The file type as reported by the client operating system  creationdate :...

    浅谈Spring如何解决循环依赖的问题

    要理解这个问题,需要从源码的角度对其实现原理进行讲解。 首先,需要了解 Spring bean 的创建过程。 Spring 中的对象实例化是通过反射实现的,而对象的属性则是在对象实例化之后通过一定的方式设置的。这个过程...

    《你必须知道的495个C语言问题》

    1.28 文件中的第一个声明就报出奇怪的语法错误,可我看没什么问题。这是为什么? 15 1.29 为什么我的编译器不允许我定义大数组,如double array[256][256]? 15 命名空间 15 1.30 如何判断哪些标识符可以使用,...

    你必须知道的495个C语言问题

    1.28 文件中的第一个声明就报出奇怪的语法错误,可我看没什么问题。这是为什么? 1.29 为什么我的编译器不允许我定义大数组,如doublearray[256][256]? 命名空间 1.30如何判断哪些标识符可以使用,哪些被保留了...

Global site tag (gtag.js) - Google Analytics