当前位置:

首页 > 编程开发 > Java并发编程的三要素是什么?

Java并发编程的三要素是什么?

1原子性1.1原子性的定义原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行。1.2原子性问题原因线程切换是产生原子性问题的原因,线程切换是为了提高CPU的利用率。以count++为例,至少需要三条CPU指令:指令1:首先,需要把变量count从内存加载到CPU的寄存器;指令2:之后,在寄存器中执行+1操作;指令3:最后,将结果写入内存(缓存机制导致可能写入的是CPU缓存而不是内存)。我们假设count=0,如果线程A在指令1执行完后做线程切换,线程A和线程B

本文目录

    Java并发编程的三要素是什么?

    1 原子性

    1.1 原子性的定义

    原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行。

    1.2 原子性问题原因

    线程切换是产生原子性问题的原因,线程切换是为了提高 CPU 的利用率。

    以 count ++ 为例,至少需要三条 CPU 指令:

    • 指令 1:首先,需要把变量 count 从内存加载到 CPU 的寄存器;

    • 指令 2:之后,在寄存器中执行 +1 操作;

    • 指令 3:最后,将结果写入内存(缓存机制导致可能写入的是 CPU 缓存而不是内存)。

    我们假设 count=0,如果线程 A 在指令 1 执行完后做线程切换,线程 A 和线程 B 按照下图的序列执行,那么我们会发现两个线程都执行了 count+=1 的操作,但是得到的结果不是我们期望的 2,而是 1。

    Java并发编程的三要素是什么?

    1.3 原子性操作

    多线程环境下中,Java 只保证了基本数据类型的变量和赋值操作才是原子性的( 注:在32位的JDK环境下,对64位数据的读取不是原子性操作*,如long、double )

    1.4 原子性问题如何解决

    如果我们能够保证对共享变量的修改是互斥的,那么,无论是单核 CPU 还是多核 CPU,就都能保证原子性了。加锁可以解决原子性问题,如使用 synchronized、lock 。

    2 可见性

    2.1 可见性定义

    可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果。

    2.2 可见性问题原因

    CPU 缓存与内存的数据一致性是导致可见性问题的原因,CPU 缓存是为了提高 CPU 的效率。

    2.3 可见性问题解决

    产生可见性问题的原因是 CPU 缓存,那我们禁用 CPU 缓存就可以了。

    • volatile 字段能禁用 CPU 缓存,解决可见性问题。

    • synchronized 和锁都可以保证可见性。

    2.4 可见性规则是什么

    可见性规则就是 Happens-Before 规则 。

    Happens-Before 规则:

    • 简单来说就是: 前面一个操作的结果对后续操作是可见的。

    • Happens-Before 约束了编译器的优化行为,虽允许编译器优化,但是要求编译器优化后一定遵守 Happens-Before 规则。

    2.5 Happens-Before 规则

    • 程序的顺序性规则

    在一个线程中,按照程序顺序,前面的操作 Happens-Before 于后续的任意操作。

    class Example {
      public void test() {
        int x = 42;   ①
        int y = 20;   ②
      }
     
    }

    ①  Happens-Before ② 。

    • volatile 变量规则

    对一个 volatile 变量的写操作, Happens-Before 于后续对这个 volatile 变量的读操作。

    • 传递性规则

    如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C。

    class Example {
      int x = 0;
      volatile int y = 0;
      public void writer() {
        x = 42;      ①
        y = 1;       ②
      }
      public void reader() {
        if (y == 1) {  ③
          // 这里x会是多少呢?
        }
      }
    }
    • ① Happens-Before ② ,满足规则1-顺序性规则。

    • ② Happens-Before ③,满足规则2-volatile 变量规则。

    • ① Happens-Before ③,满足规则3-传递性规则。如果 y == 1,则 x = 42;

    • 管程中锁的规则

    对一个锁的解锁 Happens-Before 于后续对这个锁的加锁。

    管程是一种通用的同步原语,在 Java 中指的就是 synchronized,synchronized 是 Java 里对管程的实现。

    synchronized (this) { //此处自动加锁
      // x是共享变量,初始值=10
      if (this.x < 12) {
        this.x = 12; 
      }  
    } //此处自动解锁

    假设 x 的初始值是 10,线程 A 执行完代码块后 x 的值会变成 12(执行完自动释放锁);

    线程 B 进入代码块时,能够看到线程 A 对 x 的写操作,也就是线程 B 能够看到 x==12。

    • 线程 start() 规则

    它是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。

    • 线程 join() 规则

    它是指主线程 A 等待子线程 B 完成(主线程 A 通过调用子线程 B 的 join() 方法实现),当子线程 B 完成后(主线程 A 中 join() 方法返回),主线程能够看到子线程的操作。当然所谓的“看到”,指的是对共享变量的操作。

    3 有序性

    3.1 有序性的定义

    有序性,即程序的执行顺序按照代码的先后顺序来执行。

    3.2 有序性问题原因

    编译器为了优化性能,有时候会改变程序中语句的先后顺序。

    例如:“a=6;b=7;”编译器优化后可能变成“b=7;a=6;”,在这个例子中,编译器调整了语句的顺序,但是不影响程序的最终结果。

    以双重检查代码为例:

    public class Singleton {
      static Singleton instance;
      static Singleton getInstance(){
        if (instance == null) {    ①
          synchronized(Singleton.class) {
            if (instance == null)
              instance = new Singleton();  ②
            }
        }
        return instance;
      }
    }

    上面的代码有问题,问题在 ② 操作上:经过优化后的执行路径是这样的:

    1. 分配一块内存 M;

    2. 将 M 的地址赋值给 instance 变量;

    3. 最后在内存 M 上初始化 Singleton 对象。

    优化后会导致什么问题呢?我们假设线程 A 先执行 getInstance() 方法,当执行完 ① 时恰好发生了线程切换,切换到了线程 B 上;如果此时线程 B 也执行 getInstance() 方法,那么线程 B 在执行第一个判断时会发现 instance != null ,所以直接返回 instance,而此时的 instance 是没有初始化过的,如果我们这个时候访问 instance 的成员变量就可能触发空指针异常。

    如何解决双重检查问题?变量用 volatile 来修饰,禁止指令重排序。

    public class Singleton {
      static volatile Singleton instance;
      static Singleton getInstance(){
        if (instance == null) {    ①
          synchronized(Singleton.class) {
            if (instance == null)
              instance = new Singleton();  ②
            }
        }
        return instance;
      }
    }
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。