Java并发基础:变量的线程安全

2023-11-14

一、变量的线程安全分析

成员变量和静态变量是否线程安全?

  • 如果它们没有共享,则线程安全
  • 如果它们被共享了,根据它们的状态是否能够改变,又分两种情况:

            如果只有读操作,则线程安全
            如果有读写操作,则这段代码是临界区,需要考虑线程安全

 局部变量是否线程安全?

  • 局部变量是线程安全的
  • 但局部变量引用的对象则未必

            如果该对象没有逃离方法的作用访问,它是线程安全的
            如果该对象逃离(return)方法的作用范围,需要考虑线程安全 

1.1 局部变量线程安全分析:

        如下所示,每个线程调用 test1() 方法时局部变量 i,会在每个线程的栈帧内存中被创建多份,因此不存在共享。

 public static void test1() {
        int i = 10;
        i++;
}

如下图所示,线程0和线程1都调用了test1()方法,他们都会创建一个test1的栈帧,这两个存在于各自线程内部的栈帧互不影响,局部变量i也是栈帧中私有的内存变量值,不会互相影响。

1.2 局部变量引用

 先看一个成员变量的例子: 

public class App 
{
    static final int THREAD_NUMBER = 2;
    static final int LOOP_NUMBER = 200;
    public static void main( String[] args ) throws InterruptedException {
        ThreadUnsafe test = new ThreadUnsafe();
        for(int i=0;i<THREAD_NUMBER;i++){
            //创建两个线程,对test对象执行相应的操作
            new Thread(()->{
                test.method1(LOOP_NUMBER);
            },"Thread"+(i+1)).start();
        }
    }
}
class ThreadUnsafe{
    //共享资源
    ArrayList<String> list = new ArrayList<>();

    public void method1(int loopNumber){
        for(int i=0;i<loopNumber;i++){
            //{临界区
            method2(); //先向集合中添加元素
            method3(); //在从集合中移除元素
            //}临界区
        }
    }

    private void method2(){
        list.add("1");//向集合中添加元素
    }

    private void method3(){
        list.remove(0);//从集合中移除元素
    }
}

        以上代码创建两个线程,同时对ThreadUnsafe对象中的ArrayList<String>集合执行添加以及删除元素操作。该代码可能会由于线程2还未add元素,线程1remove元素而报错

分析:

    多线程对共享资源有修改操作,产生临界区代码,会有线程安全的问题。

  • 无论哪个线程中的method2()和method3()方法引用的都是同一个对象中的list成员变量(共享资源)

与成员变量对比的局部变量示例(局部变量没有暴漏给外部):

public class App 
{
    static final int THREAD_NUMBER = 2;
    static final int LOOP_NUMBER = 200;
    public static void main( String[] args ) throws InterruptedException {
        ThreadSafe test = new ThreadSafe();
        for(int i=0;i<THREAD_NUMBER;i++){
            //创建两个线程,对test对象执行相应的操作
            new Thread(()->{
                test.method1(LOOP_NUMBER);
            },"Thread"+(i+1)).start();
        }
    }
}
class ThreadSafe{
    public void method1(int loopNumber){
        ArrayList<String> list = new ArrayList<>();
        for(int i=0;i<loopNumber;i++){
            method2(list); //先向集合中添加元素
            method3(list); //在从集合中移除元素
        }
    }

    private void method2(ArrayList<String> list ){
        list.add("1");//向集合中添加元素
    }

    private void method3(ArrayList<String> list ){
        list.remove(0);//从集合中移除元素
    }
}

以上代码不会存在线程安全的问题,分析原因如下。

分析:

  • list 是局部变量,每个线程调用时会创建其不同实例,没有共享。
  • 而 method2 的参数是从 method1 中传递过来的,与method1中引用同一个对象
  • method3 的参数分析与 method2 相同 

 二、常见线程安全类

2.1 常见线程安全类:

  • String
  • Integer 包装类
  • StringBuffer
  • Random
  • Vector
  • Hashtable
  • java.util.concurrent包下的类

        此处说的线程安全是指,多个线程调用线程安全类的同一个实例的某个方法时,是线程安全的。可以理解为:

  •  他们的每个方法是原子的
  •  但是注意:他们多个方法的组合不是原子的,

Hashtable table = new Hashtable();
// 线程1,线程2
if( table.get("key") == null) {
    table.put("key", value);
}

        上例中,类Hashtable类是线程安全的类,因此其每个方法都是原子的,即table.get()方法和table.put()方法单个看都是线程安全的。 但是,当两个方法组合在一起时,如两个线程1,2都执行上述代码,则不是线程安全的,如下图所示:

2.2 不可变类线程安全性

        String、Integer 等都是不可变类,因为其内部的状态不可以改变(只能读,不能改写),因此它们的方法都是线程安全的。

三、结束

        本文主要学习了变量的线程安全,其主要落脚点还是看是否共享资源并读写
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java并发基础:变量的线程安全 的相关文章

随机推荐

  • 清华大学,AIGC发展研究,162页PDF

    点击上方 Python与机器智能 选择 星标 公众号 第一时间获取价值内容 收集不宜 我将资料免费分享在我的星球 后续也将会持续更新 欢迎大家加入我的这个 AIGC与GPT 知识星球 价格便宜 目前已有近130人 作为一个大厂算法工程师和机
  • C++ 封装 类

    封装 可以达到 对外提供接口 屏蔽数据 对内开放数据 比如我们用struct封装的类 即知其接口 又可以直接访问其内部数据 这样却没有达到信息隐蔽的功效 而class则提供了这样的功能 屏蔽内部数据 对外开放接口 struct中所有行为和属
  • 渣硕2020暑期实习面经

    春招也基本结束了 拿了点offer 因为一开始就没有准备找区块链方向岗位 所以准备的还是研发岗 简历写了一些分布式 所以分布式理论问的也蛮多 感觉形势蛮严峻的 好多厂貌似都不开放暑期实习了 个人比较遗憾的就是微软笔试时候浏览器没搞好 导致没
  • 错误使用 network/subsasgn>network_subsasgn (line 550) net.IW{1,1} must be a 16-by-19 matrix. 出错 network

    该代码为基于PSO和BP网络的预测 清空环境 clc clear 读取数据 load CHE2 mat 节点个数 inputnum 17 hiddennum 16 outputnum 1 训练数据和预测数据 input train inpu
  • mysql 集群 一主两从环境测试,MHA主备切换

    目录 前言 1 相关安装文件 2 虚拟机 mysql数据库安装 2 1 安装VMware 15 以及 linux 操作系统 2 2 安装mysql数据库 2 2 1安装环境准备 2 2 2 mysql 数据库安装 2 3 克隆centos虚
  • Cmake零基础教程——常用语法命令

    编译选项 在cmake脚本中 设置编译选项有两种方式 1 可以通过add compile options命令 2 也可以通过set命令修改CMAKE CXX FLAGS或CMAKE C FLAGS 存在即合理 那么使用这两种方式存在怎样的区
  • ssh和ftp登录的几种方式

    ssh登录的几种方式 本文为https www bilibili com video av755468030 笔记 1 密码账号登录 ssh p 1234 name 目标ip p 为指定端口 name为用户名 2 使用公钥私钥登录 获取指定
  • IDEA中javaweb项目导入外部jar包

    IDEA中javaweb项目导入外部jar包 打开Project Structure 选中Modules 选择Dependencies 点击 选择要导入的jar包或jar包文件夹 选中要使用的jar包或jar包文件夹 点击ok 如果只是按照
  • excel导出功能

    安装excel所需依赖和按需加载 由于 Export2Excel不仅依赖js xlsx还依赖file saver和script loader 所以你先需要安装如下命令 npm install xlsx file saver S npm in
  • React传参和定义变量

    react 声明变量 react传参
  • 学习linux内核的经典书籍介绍

    有关内核的书籍可以用汗牛充栋来形容 不过只有一些经典的神作经住了考验 首先是5本久经考验的神作 个人概括为 2 1 2 第一个2是指2本全面讲解内核的书 中间的1指1本讲解驱动开发的书 后面的2则指2本有关内核具体子系统的书 你是否想到了某
  • vscode 静态语法检测插件C/C++ Advanced Lint,ubuntu20.04安装clang、cppcheck

    远程环境 ubuntu20 04 本地开发环境 windows 11 开发IDE vscode 一 ubuntu20 04安装clang 安装llvm apt get install llvm 2 安装clang apt get insta
  • 11-数据结构-双链表的创建-输出-初始化-插入-删除

    问题 双链表的创建 输出 初始化 插入 删除 思路 搞清楚双链表是怎么样的 多了一个前指针 此外每次链接的时候 都是先连接好后面的再连接前面的 直接看代码吧 代码如下 include
  • 思科实验 voip通信的配置(内附命令超详细)

    作者 小刘在C站 个人主页 小刘主页 每天分享云计算网络运维课堂笔记 努力不一定有回报 但一定会有收获加油 一起努力 共赴美好人生 夕阳下 是最美的绽放 树高千尺 落叶归根人生不易 人间真情 目录 一 实验目的和要求 二 实验设备
  • Python疫情数据爬取与可视化

    使用Python爬取腾讯新闻疫情数据 并使用pyecharts可视化 绘制增长人数地图 柱状图 折线图 文章目录 1 分析网页 2 导入模块 3 抓取数据 4 提取数据并写入Excel 5 国内各地区现有确诊人数地图 6 国内各地区现有确诊
  • 秒懂边缘云

    作者 辰舒 章节内容 如何配置解析记录 已有CNAME A记录时如何配置 如何检查解析配置是否生效 解析基本原理 前言 上个章节中我们学习了如何根据业务情况添加CDN域名并配置源站 但在添加完成后 域名尚未真正接入CDN服务 我们需要将域名
  • Kafka

    1 概述 1 1 定义 Kafka是一个分布式的基于发布 订阅模式的消息队列 主要应用于大数据实时处理领域 优势 kafka可以做到 使用非常普通的硬件 也可以支持每秒数百万的消息读写 MQ 代表消息队列 kafka只是众多mq中一款产品
  • Shell脚本编程入门--Day2

    文章目录 几个简单内置shell命令 shell字串的语法 计算变量长度的各种玩法 批量修改文件名 特殊shell扩展变量 实际应用 父子shell 创建进程列表 创建子shell 几个简单内置shell命令 echo n 不换行输出 e
  • 牛客面试高频算法题js(最长无重复子数组、删除链表的倒数第n个节点、大数加法、按之字形顺序打印二叉树、链表相加(二))

    最长无重复子数组 描述 给定一个长度为n的数组arr 返回arr的最长无重复元素子数组的长度 无重复指的是所有数字都不相同 子数组是连续的 比如 1 3 5 7 9 的子数组有 1 3 3 5 7 等等 但是 1 3 7 不是子数组 数据范
  • Java并发基础:变量的线程安全

    一 变量的线程安全分析 成员变量和静态变量是否线程安全 如果它们没有共享 则线程安全 如果它们被共享了 根据它们的状态是否能够改变 又分两种情况 如果只有读操作 则线程安全 如果有读写操作 则这段代码是临界区 需要考虑线程安全 局部变量是否