idea这么牛,居然能判断当前环境线程是否安全????

‘StringBuffer stringBuffer’ may be declared as ‘StringBuilder’ less… (Ctrl+F1)
Inspection info: Reports any variables declared as java.lang.StringBuffer which may be more efficiently declared as java.lang.StringBuilder. java.lang.StringBuilder is a non-thread-safe replacement for java.lang.StringBuffer, available in Java 5 and newer.
This inspection only reports if the project or module is configured to use a language level of 5.0 or higher.

以上内容用于搜索引擎抓取,也是写这篇博客的原因。

前言

我从学习java开始,就用的idea,可能我还是一个年轻java开发者。不得不说,idea真的很智能、很顺手,什么重复代码片段抽取、全局搜索、智能提示,我真的是爱不释手。也让我非常佩服idea的开发者,真的是太厉害了。在使用过程中,我也记录了很多快捷键、使用技巧:
在这里插入图片描述有空了一定要把这些记录整理出来,写成一篇博客,跑题了。

基于这些原因,对于代码中idea的提示,我都会看一下提示的原因,然后思考一下为什么会这样提示。今天的这篇博客也是来源于idea的一个提示

idea的提示

今天我在看别人写的代码时,idea给了一个提示,如下图:
在这里插入图片描述我当时就惊呆了,idea居然提示我:StringBuffer或许可以声明为StringBuilder!!!! 也就是idea建议在这里使用StringBuilder而不是使用StringBuffer。关于StringBuffer和StringBuilder,我简单的说一下,可以选择性跳过

因为字符串底层用的是char数组,数组长度不可变,所以字符串本身也是不能改变的。字符串的那些什么replace方法,看起来好像是在修改字符串,其实都是新new了一个字符串对象。我们平时在拼接字符串时,最顺手的可能就是直接用+进行拼接了,这样会浪费内存,因为会产生许多我们不关心的字符串对象,所以在进行多次拼接时,使用StringBuilder或者StringBuffer更好。而Builder和Buffer的区别是,Buffer中所有的方法都加了synchronized,所以是线程安全的,builder虽线程不安全,但是在单线程下,速度更快

idea的开发者不会不知道Builder是线程不安全的,但是居然还给我提示,难道idea不怕开发者听从了这个建议而使代码出现问题吗?我觉得这个提示不是随随便便就提示的,并不是idea仅仅觉得Builder更快,就忽略了Builer线程不安全这个问题。那难道说,idea可以检测到当前运行环境是否是线程安全的??那idea这也太牛了吧,而且现在只是编译时期,没到运行时期,他咋知道这段代码会不会被并发呢?

那我就想,假如,我把Buffer放在一个线程不安全的坏境下,idea还是会提示我StringBuffer stringBuffer’ may be declared as 'StringBuilder吗?,

验证StringBuilder线程不安全

正如上说的那样,StringBuffer线程安全,是因为他的所有方法都加了synchronized关键字,而Builder没有,所以我们只要用多个线程对同一个StringBuilder中的方法进行并发,那么StringBuilder大概率会出问题。示例代码

public class StringBuilderDemo {

    public static void main(String[] args) throws InterruptedException {
        test1();
    }

    public static void test1() throws InterruptedException {
        StringBuilder stringBuilder = new StringBuilder();
        StringBuffer stringBuffer = new StringBuffer();


        for (int i = 0; i < 10; i++){
            new Thread(() -> {
                for (int j = 0; j < 1000; j++){
                    stringBuilder.append("a");
                    stringBuffer.append("a");
                }
            }).start();
        }
        

        Thread.sleep(100);
        System.out.println("builder length:"+stringBuilder.length());
        System.out.println("buffer  length:"+stringBuffer.length());
        
    }
}

开10个线程,对同一个builder和buffer进行append,每个线程append1000次。某次运行结果

builder length:9996
buffer  length:10000

所以builder是线程不安全的。

情况分析

我在写上面那段段示例代码时就发现了端倪,当我分别把Builder和Buffer 声明并new出来时,就提示我 StringBuffer stringBuffer’ may be declared as 'StringBuilder ,
在这里插入图片描述

但是一旦我将多线程那段代码放开时,StringBuffer stringBuffer’ may be declared as 'StringBuilder 这个提示就会消失。只是提示我,buffer被更新了,但是没有被查询,就是没有使用更新过后的内容,上面的builder也是同样的提示
在这里插入图片描述

所以说idea是能够检测到,你的代码中,是否对Buffer进行了并发,包括使用线程池,如下图,并没有提示StringBuffer stringBuffer’ may be declared as 'StringBuilder
在这里插入图片描述

经过上面的推导,我们得出了一个肤浅的结论,idea能够检测到,开发者写的代码是否对Buffer进行了并发,如果没有,idea就会提示开发者StringBuffer stringBuffer’ may be declared as 'StringBuilder 。反正你又没并发操作Buffer,那还不如用builder更快,我想这是idea开发者在开发这个功能时所想的

为什么说是肤浅的结论呢?因为我由此又想到了两个问题,这两个问题会给上面的结论做限制

问题1

能检测到我当前代码是否对buffer进行了并发,那如果我将buffer传递给别的方法呢?idea还会继续到那个方法里面去检测有没有对这个buffer进行并发吗?

我随便写了一个方法test1,这个方法接收一个StringBuffer参数
在这里插入图片描述我在当前方法里面不对buffer进行并发,还是提示我StringBuffer stringBuffer’ may be declared as 'StringBuilder,而一旦我将buffer变量传递到test1方法中去,这个提示就会消失。
在这里插入图片描述

但实际上我在test1方法中,并没有对传递过来的buffer进行并发操作,只是简单的打印而已。所以idea的检测范围,只是在StringBuffer声明的那个方法内,一旦将buffer传递到别的方法中,不管那个方法有没有对buffer进行并发,idea都不再提示

其实想想也是,如果这个StringBuffer被传递到各个方法,那需要跑到各个方法中去检测,得不偿失,所以只在StringBuffer声明的方法内检测,是最好的选择。既达到了提示开发者的效果,又没有过度的去检测,过度检测可能会使idea吃更大的内存

问题2

上面所说的,都是在方法内部,检测的开发者的代码(准确来说是声明StringBuffer的方法内)有没有对StringBuffer进行并发,那如果是在别的地方对声明StringBuffer的方法进行并发呢?idea是无法检测到的,因为可能是别人使用我的jar包、依赖啥的,但是idea为啥还是敢提示呢?就比如说这样:

在这里插入图片描述test1方法是new StringBuffer 拼接1000个a,但是我在main方法中,创建了10个线程,对这个test1方法进行并发,但实际上这样并不会出现线程安全问题,因为没有出现多个线程对同一个StringBuffer中的同一个方法进行并发。虽然有10个线程对test1方法进行并发,但是每个线程进来之后,都各自new了个StringBuffer,然后各操作各的,所以不会出现线程安全问题。

局部变量,在方法内部,只要在方法内不调用其他方法将这个变量传递出去,这个变量就不会存在线程安全问题,所以也不用担心对这个方法进行并发。

那如果是成员变量呢?测试了一下,当StringBuffer声明成一个成员变量时,不管是否在这个类的方法中对StringBuffer的方法进行并发,都不再会提示,这是为啥呢?因为成员变量可能会会有线程安全问题, 就算在当前类中没有对这个成员变量进行并发,也可以通过反射拿到这个成员变量,然后在别的地方对这个成员变量进行并发。

总结

  1. 如果StringBuffer是成员变量,无论如何idea都不会提示StringBuffer stringBuffer’ may be declared as 'StringBuilder,因为idea无法保证StringBuffer不会在这个类的外部不被其他方法进行并发,即便StringBuffer是被private修饰的,没有提供对外暴露的方法,但是依然可以通过反射拿到这个StringBuffer,进行并发操作
  2. 如果StringBuffer是局部变量,当在这个局部范围内(方法内)没有对StringBuffer的方法进行并发,并且没有将StringBuffer传递给别的方法,idea就会提示StringBuffer stringBuffer’ may be declared as 'StringBuilder,因为在这种情况下,外部无法拿到局部的StringBuffer。

说点题外话,idea还是比较严谨的,线程安全问题,的确是一个比较大头的东西,idea提示也是非常委婉,即便是根据一些逻辑判断,才触发这个提示,但是也是用的:或许

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
StringBuilderStringBuffer都是用于操作字符串的类。 StringBuilder类的构造函数如下所示:public StringBuilder() { super(16); } ,它会创建一个初始容量为16的StringBuilder对象。 StringBufferStringBuilder的使用场景是类似的,都可以用于拼接和修改字符串。然而,由于StringBuilder相较于StringBuffer有速度优势,所以多数情况下建议使用StringBuilder类 。只有在应用程序要求线程安全的情况下,才必须使用StringBuffer类 。 总结来说,如果你的应用程序不需要考虑线程安全问题,可以使用StringBuilder类来操作字符串。如果你的应用程序需要考虑线程安全,那么就应该使用StringBuffer类来代替StringBuilder类。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [关于StringBuilderStringBuffer你了解多少?](https://blog.csdn.net/weixin_32300523/article/details/106383924)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [String、StringBufferStringBuilder的详解](https://blog.csdn.net/weixin_39671217/article/details/129192992)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值