题目:什么是线程安全
难度:low
标签:java/lock, general/knowledge
评分:⭐⭐⭐☆☆
线程安全本质映射的问题就是线程不安全,然后它更衍生,其实它名字应该是多线程下的安全,单线程不存在所谓线程安全的问题。多线程下出现线程安全问题,指的是对有状态的情况下,不同的线程做不同的修改,导致信息错乱,应该是这么一种情况,是信息不安全。然后为了处理这个事,这个信息不安全的问题,才衍生了线程安全的这么一个事情。所以所谓线程安全,就是处理多线程下有状态的数据的变更。要保证这个线程更新数据的时候,各个线程看到的是自己的数据,或者是大家同一时间只能有一个人更改,其他人等待。比如线程锁,锁住一个进程,锁住一个数据,这个对象要修改的时候,只能由一个线程去进行修改,其他线程需要等待。另外还有前置的条件,就是线程安全有状态,无状态它就线程安全了,没有多线程并行修改的影响,就不会有相互的线程安全问题存在,也就多线程可以正常使用了。定了两个方向,一个是 Redis 选择,就单线程,大家就单线程走,没有什么多线程并发的问题,我也不做处理,大家就一个线程跑。Java 里对于并发线程安全,就是常规的加锁或者是无状态,这么去处理。就比如线程栈、任务栈,任务栈内的数据,它不逃离这个方法栈,它就在方法栈内执行,它就不会涉及这个问题,不会有多线程进来去影响。
优点:抓到"多线程+有状态"才是前提这一关键直觉;举了 Redis 单线程、方法栈局部变量等具体例子;有工程实例感
不足:表述冗长、逻辑跳跃;未从"共享资源"核心点切入;"锁住进程"表述不准(应为锁对象/代码块);未提到底层机制(JMM/可见性/有序性);未系统归纳三个层次
补充:标准定义——多线程访问共享资源时,任意时刻执行结果都符合预期;三个层次:互斥、可见性、有序性;实现手段:synchronized、Lock、volatile、AtomicXxx、ThreadLocal、无状态化
核心考点定位:能否说清"多线程+共享资源"这个前提,以及互斥/可见性/有序性三个层次。
知识点拆解:
按「底层原理 → 设计权衡 → 工程实践」递进排列。
考察方向:
延伸递进面试题:
面试官您好,线程安全的本质是"多线程访问共享可变资源时,任意时刻的执行结果都符合预期"。我把它拆成三个层次来说。
第一个层次是互斥——同一时刻只能有一个线程修改共享数据,避免"读-改-写"竞态。经典例子是 i++,其实是三条指令:读 i、i+1、写回,两个线程同时执行就会丢更新。synchronized 和 Lock 就是干这个的。
第二个层次是可见性——一个线程改了共享变量,其他线程必须能立刻看到新值。这里有个反直觉的点:现代 CPU 每个核有自己的 L1 缓存,一个核改了主存,另一个核的缓存不会立刻失效,JIT 还会重排指令。volatile 就是给编译器加屏障、给 CPU 加 MESI 协议失效,强制写操作刷到主存、读操作从主存取。
第三个层次是有序性——编译器和 CPU 会重排指令来提升性能,但有时候会破坏业务语义,比如双重检查锁单例,如果不加 volatile,实例可能以"半初始化"的状态被其他线程看到。
工程上的应对手段我大概分四类:一是强制同步,synchronized 和 ReentrantLock,重量级但灵活;二是无锁原子,AtomicXxx 和 CAS,性能好但有 ABA 和自旋开销;三是弱化共享,ThreadLocal、不可变对象、纯函数;四是单线程化,比如 Redis 主线程、Netty 单 Reactor。
举几个反例说明"看起来安全实际不安全":ConcurrentHashMap 的 get/put 安全,但复合操作还是要同步;HashMap 并发 put 甚至会死循环;SimpleDateFormat 是经典的非线程安全类。
这就是我对线程安全的理解。
题目:什么是线程安全
难度:low
标签:java/lock, java/concurrency
评分:⭐⭐⭐⭐☆(4/5)
练习次数:2
线程安全核心是保证在多线程并发访问共享资源的情况下,每个线程都获取到符合预期的结果;
java中核心是使用JMM定义的内存管理规范方式实现线程安全;
线程安全的核心是三个方面,互斥,可见性,有序性;
分别对应的处理方案,互斥方面主要是锁,以及ThreadLocal走的每个线程独立的一个数据实现互斥;
可见性方面主要使用synchronized和volatile去实现,依据是操作系统的底层命令将数据强刷进入到cpu主存中给所有线程共享;
有序性方面是基于jmm的happend-before原则,以及读写屏障保证有序性
优点:三个层次(互斥/可见性/有序性)这次讲清楚了,比 09-26 的结构感明显提升;能主动挂到 JMM 与 happens-before 上,层次正确
不足:① "ThreadLocal 实现互斥" 说法不准——ThreadLocal 是消除共享,不是互斥;② 可见性归因于"操作系统底层命令强刷主存"过于笼统,准确说是 MESI 缓存一致性 + 内存屏障(lock 前缀 / LoadLoad 等);③ 未提"共享可变"这个前提,也没给反例
补充:三层次之外还有第四层——原子性(i++ 不是原子操作);实现谱系:强制同步 / 无锁 CAS / 弱化共享(ThreadLocal、不可变)/ 单线程化
ℹ️ 完整讲解见上方首次记录(2026-09-26)