当前位置: 首页 > news >正文

Java——线程不安全的原因(图解)

一、多线程修改同一个变量

💡 count自增100_0000次,并发执行:

count++实际由3部分组成:

  • 从内存读数据到cpu(load),

  • cpu寄存器,进行自增操作(add),

  • cpu寄存器又返回数据到内存(save).

图解:

代码:

class Counter {
    public int count = 0;

    public void incerse() {
        count++;
    }
}
public class Thread2 {
    public static void main(String[] args) {
        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50_0000; i++) {
                counter.incerse();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50_0000; i++) {
                counter.incerse();
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(counter.count);
    }
}

预期结果:100_0000
实际结果:


  • 单线程修改同一变量,安全;

  • 多线程读同一变量,安全;

  • 多线程修改不同变量,安全.

二、抢占式

💡 各线程之间是抢占式执行,程序猿无法得知其执行的顺序.

代码:

public class Thread3 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println("t1……");
        });
        t1.start();
        System.out.println("main……");
    }
}

预期结果:先执行t1……,再执行main……
实际结果:

原因:操作系统内核的随机调度,程序猿无法干预.

三、原子性

💡 不可拆分的最小单位就是原子.

原子:
 a = 10; //一步到位 
非原子操作:
 b++; //上述3步操作

四、内存可见性

一个线程读,一个线程写,很容易导致代码优化,产生误判,从而导致的不安全问题.

图解:

代码:

public class Thread4 {
    static int flag = 0;

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

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    if(flag != 0) {
                        System.out.println("线程执行中……");
                        break;
                    }

                }
                System.out.println("线程执行结束");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                flag = 1;
            }
        });
        t1.start();
        t2.start();
    }
}

结果:

五、指令重排序

代码的执行顺序和逻辑顺序不一致,也是为了提升效率造成的.

图解:

代码:

Test t = new Test();

原因:
在这里插入图片描述

相关文章:

  • [数据结构]~双向+循环链表从(0~1)
  • 【开学季】再见大一,你好大二 | 完成自己的未完成
  • java毕业设计网站SSM版学生选课系统[包运行成功]
  • 【计算机网络】第六章:应用层
  • FS03MR12A6MA1LBBPSA1 1200V 400A 紧凑型 六单元模块
  • 系统篇: ubuntu 18.04 ROS1 和 ROS2 环境搭建
  • 贪心算法 - 买卖股票的最佳时机|| + 分割平衡字符串
  • ActiveReports.NET 16.2RPX 部分报告的完全支持
  • 专业英语第八章Communications and Networks测试题
  • 【Linux操作系统】-- 多线程(三)-- 线程池+单例模式+读写者模型
  • Pinia实操配置,Vuex的替代品
  • flume系列(一)部署示例及组件介绍
  • 【SpringBoot】静态资源导入探究
  • Redis cache-aside模型-分布式锁等问题研究
  • TypeScript 中 Type 和 Interface 有什么区别?
  • [iOS]Core Data浅析一 -- 启用Core Data
  • 【Leetcode】104. 二叉树的最大深度
  • 【Linux系统编程】快速查找errno错误码信息
  • 4个实用的微服务测试策略
  • Angular 2 DI - IoC DI - 1
  • javascript 哈希表
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • 创建一个Struts2项目maven 方式
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 浏览器缓存机制分析
  • 用Visual Studio开发以太坊智能合约
  • 云栖大讲堂Java基础入门(三)- 阿里巴巴Java开发手册介绍
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • #Java第九次作业--输入输出流和文件操作
  • (06)金属布线——为半导体注入生命的连接
  • (3)llvm ir转换过程
  • (a /b)*c的值
  • (八)Flask之app.route装饰器函数的参数
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (一) springboot详细介绍
  • (转)visual stdio 书签功能介绍
  • .form文件_SSM框架文件上传篇
  • .net core webapi 大文件上传到wwwroot文件夹
  • .NET Micro Framework初体验(二)
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET多线程执行函数
  • .Net中间语言BeforeFieldInit
  • @Controller和@RestController的区别?
  • [.net] 如何在mail的加入正文显示图片
  • [20150629]简单的加密连接.txt
  • [Android]如何调试Native memory crash issue
  • [AutoSAR 存储] 汽车智能座舱的存储需求
  • [C#]C# OpenVINO部署yolov8图像分类模型
  • [CISCN 2019华东南]Web11
  • [CVPR2021]Birds of a Feather: Capturing Avian Shape Models from Images
  • [Electron]ipcMain.on和ipcMain.handle的区别