news 2026/4/15 15:37:35

Java面试:并发编程三要素你真的掌握了么?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java面试:并发编程三要素你真的掌握了么?

文章目录

  • Java面试:并发编程三要素你真的掌握了么?
    • 一、为什么并发编程这么难?
    • 二、原子性:我要一口气做完这件事
      • 什么是原子性?
        • 1. 使用 synchronized 关键字
        • 2. 使用不可中断的操作(如加法)
        • 3. 使用 AtomicInteger 类
    • 三、可见性:我要让所有人看到我做的修改
      • 什么是可见性?
        • 1. 使用 volatile 关键字
        • 2. 使用 synchronized
        • 3. 使用 Atomic系列类
    • 四、有序性:我要按顺序执行
      • 什么是有序性?
      • 如何保证有序性?
        • 1. 使用 synchronized
        • 2. 使用 volatile 和 final 关键字
        • 3. 使用 Thread.sleep()
    • 五、总结
    • 希望这篇文章能帮助你更好地理解并发编程中的原子性、可见性和有序性问题!
      • 📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!

Java面试:并发编程三要素你真的掌握了么?

大家好,我是闫工!今天咱们来聊一聊Java面试中必问的并发编程三要素——原子性、可见性和有序性。这三个概念看似简单,但很多同学在实际应用中还是容易搞混或者理解不深入,导致面试时被问住。别担心,闫工带你一步步拆解这些知识点,保证你不仅能背出来,还能灵活运用!


一、为什么并发编程这么难?

在开始正题之前,闫工先抛一个问题:为什么并发编程这么难?

想象一下,我们平时写代码的时候,程序是按顺序执行的。比如,A操作执行完之后,接着执行B操作,中间不会有其他人插队或者打断。但在并发环境下,多个线程同时运行,可能会有以下问题:

  1. 原子性问题:一个操作本来应该是不可分割的整体(比如读取和修改一个变量),但由于多个线程的干扰,导致这个操作被“拆开”了。
  2. 可见性问题:一个线程对共享变量的修改,其他线程可能看不到或者看到的是过时的数据。
  3. 有序性问题:由于编译器优化或CPU指令重排,代码的实际执行顺序可能与你写的顺序不一致。

这些问题会导致我们的程序出现各种奇怪的现象,比如数据不一致、逻辑错误等。因此,要想写出正确的并发程序,必须掌握这三个要素!


二、原子性:我要一口气做完这件事

什么是原子性?

原子性指的是一个操作要么完全执行,要么完全不执行,不会被中断或部分执行。就像我们常说的“交易要么成功,要么失败”,没有第三种可能。

在Java中,如何保证原子性呢?主要有以下几种方式:

1. 使用 synchronized 关键字

synchronized 是Java中最常用的同步机制。它可以修饰方法或者代码块,确保同一时间只有一个线程可以执行被synchronized保护的代码。

publicclassAtomicExample{privateintcount=0;publicsynchronizedvoidincrement(){count++;}}

闫工提醒:虽然 synchronized 简单易用,但它可能会导致性能问题。如果需要更高的性能,可以考虑使用更细粒度的锁机制,比如 ReentrantLock。

2. 使用不可中断的操作(如加法)

某些操作本身是原子性的,不需要额外的同步措施。例如,对一个32位整数进行加法操作在Java中是一个原子操作,因为JVM保证了这种操作的原子性。

publicclassAtomicExample{privateintcount=0;publicvoidincrement(){// 这是一个原子操作count++;}}
3. 使用 AtomicInteger 类

从Java 1.5开始,提供了Atomic系列类(如AtomicInteger、AtomicLong等),这些类内部通过CAS(Compare and Swap)算法实现无锁的原子操作。

importjava.util.concurrent.atomic.AtomicInteger;publicclassAtomicExample{privateAtomicIntegercount=newAtomicInteger(0);publicvoidincrement(){// CAS算法保证了这个操作的原子性count.getAndIncrement();}}

三、可见性:我要让所有人看到我做的修改

什么是可见性?

可见性指的是当一个线程对共享变量进行修改后,其他线程能够立即看到这个修改。如果不保证可见性,可能会出现“脏读”或“旧数据”的问题。

在Java中,如何解决可见性问题呢?主要有以下几种方式:

1. 使用 volatile 关键字

volatile 是一个轻量级的同步机制,它确保被修饰的变量对所有线程都是可见的。当一个线程修改了volatile变量后,其他线程能够立即看到这个修改。

publicclassVisibilityExample{privatevolatilebooleanflag=false;publicvoidsetFlag(){flag=true;}publicvoidcheckFlag(){while(!flag){// 等待flag被设置为true}}}

闫工提醒:虽然 volatile 能保证可见性,但它不能保证原子性。比如,count++这样的操作如果用volatile修饰,仍然有可能出现线程安全问题。

2. 使用 synchronized

synchronized不仅能保证原子性,还能保证可见性。当一个线程退出synchronized代码块时,它会将修改过的共享变量写入主内存,并让其他线程看到这些修改。

publicclassVisibilityExample{privateintcount=0;publicsynchronizedvoidincrement(){count++;}publicsynchronizedintgetCount(){returncount;}}
3. 使用 Atomic系列类

Atomic系列类不仅保证原子性,还隐式地保证了可见性。例如,getAndIncrement()方法在执行时会确保其他线程能看到最新的值。

importjava.util.concurrent.atomic.AtomicInteger;publicclassVisibilityExample{privateAtomicIntegercount=newAtomicInteger(0);publicvoidincrement(){count.getAndIncrement();}}

四、有序性:我要按顺序执行

什么是有序性?

有序性指的是程序的执行顺序应该与代码书写的顺序一致。但在并发环境下,由于编译器优化或CPU指令重排,可能会导致实际执行顺序与预期不符。

比如,下面这段代码看似逻辑清晰,但可能因为指令重排导致问题:

publicclassOrderingExample{inta=0;booleanflag=false;publicvoidwrite(){a=1;// 操作1flag=true;// 操作2}publicvoidread(){if(flag){// 如果看到flag是trueSystem.out.println(a);// 是否能保证a是1?}}}

在单线程环境下,read()方法会输出1。但在多线程环境下,由于指令重排,可能会出现以下情况:

  1. 操作2(设置flag为true)被提前执行。
  2. read()方法先读到flag是true,然后去读a的值,这时候a可能还没有被赋值。

因此,我们需要通过一些机制来保证有序性。

如何保证有序性?

1. 使用 synchronized

synchronized 不仅能保证原子性和可见性,还能确保执行顺序与代码书写的顺序一致。因为当一个线程释放锁时,它会将所有修改写入主内存,并且其他线程在获取锁之前必须读取最新的值。

publicclassOrderingExample{inta=0;booleanflag=false;publicsynchronizedvoidwrite(){a=1;// 操作1flag=true;// 操作2}publicsynchronizedvoidread(){if(flag){// 如果看到flag是trueSystem.out.println(a);// 能保证a是1}}}
2. 使用 volatile 和 final 关键字

volatile 可以防止指令重排,但只能在特定情况下使用。例如,如果一个字段被final修饰,并且在构造函数中被正确初始化,那么其他线程在读取这个字段时能看到最新的值。

publicclassOrderingExample{privatefinalinta;privatevolatilebooleanflag=false;publicOrderingExample(intvalue){this.a=value;// final字段必须在构造函数中赋值this.flag=true;}publicvoidread(){if(flag){// 能看到a的最新值System.out.println(a);}}}
3. 使用 Thread.sleep()

虽然不推荐,但在某些情况下可以通过让线程暂停一段时间来避免指令重排问题。但这不是一个可靠的解决方案。

publicclassOrderingExample{inta=0;booleanflag=false;publicvoidwrite(){a=1;// 操作1try{Thread.sleep(1);// 让线程暂停一段时间}catch(InterruptedExceptione){e.printStackTrace();}flag=true;// 操作2}publicvoidread(){if(flag){// 能看到a的最新值System.out.println(a);}}}

五、总结

特性synchronizedvolatileAtomic系列类
原子性
可见性是(但不能保证原子性)
有序性部分支持部分支持(隐式通过内存屏障)

在实际开发中,我们需要根据具体需求选择合适的机制。如果需要同时保证原子性和可见性,可以考虑使用synchronized或Atomic系列类;如果只是简单的可见性问题,可以尝试使用volatile。

此外,还需要注意以下几点:

  1. 避免不必要的同步:过多的同步会影响程序性能。
  2. 合理使用锁粒度:尽量缩小锁的范围,减少阻塞时间。
  3. 线程安全数据结构:对于集合类,可以考虑使用ConcurrentHashMapCopyOnWriteArrayList等线程安全的数据结构。

希望这篇文章能帮助你更好地理解并发编程中的原子性、可见性和有序性问题!

📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!

成体系的面试题,无论你是大佬还是小白,都需要一套JAVA体系的面试题,我已经上岸了!你也想上岸吗?

闫工精心准备了程序准备面试?想系统提升技术实力?闫工精心整理了1000+ 套涵盖前端、后端、算法、数据库、操作系统、网络、设计模式等方向的面试真题 + 详细解析,并附赠高频考点总结、简历模板、面经合集等实用资料!

✅ 覆盖大厂高频题型
✅ 按知识点分类,查漏补缺超方便
✅ 持续更新,助你拿下心仪 Offer!

📥免费领取👉 点击这里获取资料

已帮助数千位开发者成功上岸,下一个就是你!✨

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 1:03:01

Gemma 3模型技术演进与边缘计算革命

在人工智能技术快速迭代的今天,轻量级多模态模型正成为推动AI普惠化的关键力量。Gemma 3作为Google最新推出的开源视觉语言模型家族,凭借其创新的技术架构和卓越的边缘部署能力,正在重新定义AI模型的应用边界。本文将从技术演进、边缘部署策略…

作者头像 李华
网站建设 2026/4/15 5:44:11

小白也能学会:通过SSH访问远程TensorFlow深度学习平台

小白也能学会:通过SSH访问远程TensorFlow深度学习平台 在实验室里,一个新来的研究生花了整整三天才把本地的CUDA、cuDNN和TensorFlow环境配通;而在隔壁工位,另一位同学只用一条SSH命令就登录到了预配置好的远程服务器,…

作者头像 李华
网站建设 2026/4/3 4:46:28

基于java + vue物流管理系统(源码+数据库+文档)

物流管理 目录 基于springboot vue物流管理系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue物流管理系统 一、前言 博主介绍:✌️大…

作者头像 李华
网站建设 2026/4/12 11:51:30

Multisim仿真电路图实例:直流偏置放大电路调试技巧

用Multisim调试共射放大电路:从Q点设置到频率响应优化的实战指南你有没有遇到过这种情况?辛辛苦苦搭好一个BJT放大电路,结果输出波形不是削顶就是失真严重,增益还远低于理论值。电源一加,信号一输,示波器上…

作者头像 李华
网站建设 2026/4/3 5:13:04

2025,我的技术创作爆发:半年三百篇博文的成长奇迹

半年时间,从零到三百篇原创,从普通开发者到“新星创作者”——记录我在Java后端领域的技术觉醒之旅一、创作爆发:半年三百篇的惊人旅程 2025年6月底,我做出了一个改变技术生涯的决定:开始系统性地进行技术写作。从那天…

作者头像 李华
网站建设 2026/4/12 23:13:59

diskinfo检测SSD磨损情况保障TensorFlow数据安全

diskinfo检测SSD磨损情况保障TensorFlow数据安全 在深度学习项目中,我们常常把注意力集中在模型结构、训练速度和GPU利用率上。但你有没有遇到过这样的情况:一个正在收敛的训练任务突然中断,日志写入失败,Jupyter Notebook无法保存…

作者头像 李华