回答
线程安全的本质是内存安全,在 Java 中我们绝大多数的数据都是存储在 Java 堆中的,而 Java 堆是所有线程共享的。当多个线程访问同一个对象时,如果能够获得预期的结果,那么我们就会说这个对象线程安全,反之线程不安全。
一个对象是否线程安全需要考虑两个问题:
共享资源
首先我们的资源需要是共享的,例如线程独享的局部变量我们是无需考虑其线程安全问题的。多个线程访问和修改同一块资源,可能会 导致资源状态的不一致。
竞争条件
如果多个线程同时访问共享资源,并试图同时修改它,就会产生竞争条件。
同时,线程安全还问题还涉及三个核心问题:
- 原子性
原子性指的是一个或多个操作在 CPU 执行的过程中是不可分割的、执行过程中不可被中断的一整套操作。如果一个操作是原子的,那么这些操作要么全部成功执行并完成,要么全部不执行,不会出现中间状态。比如下面这个操作就不是原子性的:
i++
因为它包含了三个步骤:
- 读取
i
的值。 - 增加
i
的值。 - 将新值写回到
i
的内存地址。
在多线程环境下,如果我们不采取有效的保护措施,则该操作就是线程不安全的。
更多关于原子性的阅读:什么是原子性?volatile能保证原子性吗?
- 可见性
可见性是指一个线程对共享变量的修改,能够及时被其他线程看到。由于 Java 的内存模型(JMM)的存在,线程对变量的操作并不总是直接作用于主内存,而是可能会被缓存到线程的工作内存中(如 CPU 缓存)。
更多关于可见性的阅读:什么是可见性?volatile 是如何保证可见性的?
- 有序性
有序性指的是程序在执行过程中,操作的顺序可以按照程序的代码顺序执行。由于编译器和处理器的优化(重排序),代码的实际执行顺序可能与代码的书写顺序不同。
更多关于有序性的阅读:知道指令重排吗?volatile 是如何保证有序性的?
扩展
Java 提供了多种方案来保证线程安全问题,详细情况请阅读:有哪些方案可以实现线程安全?
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。