IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> idea这么牛,居然能判断当前环境线程是否安全???? -> 正文阅读

[开发工具]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提示也是非常委婉,即便是根据一些逻辑判断,才触发这个提示,但是也是用的:或许

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 16:53:33  更:2021-08-23 16:54:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/22 19:31:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码