线程安全指多线程访问共享资源时行为符合预期、结果确定且无数据污染;i++因非原子性(读-改-写三步)、可见性缺失和有序性错乱而不安全;volatile仅解决前两者,synchronized通过Monitor实现原子性、可重入与自动释放;AtomicInteger基于CAS适用于单变量原子操作,但不支持多步协同;根本难点在于识别隐式共享与合理控制锁粒度。

线程安全不是“加了锁就安全”,而是指多个线程同时访问同一对象或变量时,**程序行为始终符合预期,结果确定、无数据污染**。比如一个计数器被 10 个线程各加 100 次,最终必须是 1000 —— 少了,就是不安全;多了,也是不安全。
为什么 i++ 不是线程安全的?
表面看是一行代码,实际分三步:读取 i → 计算 i+1 → 写回 i。两个线程可能同时读到 i = 5,都算出 6,再都写回去,结果还是 6(本该是 7)。这就是原子性被破坏。
- 可见性缺失:线程 A 修改了
count,但没及时刷到主内存,线程 B 还在用自己缓存的老值 - 有序性错乱:JVM 或 CPU 可能重排序指令,比如把“初始化对象”和“发布引用”调换顺序,导致其他线程看到未构造完成的对象(典型单例双重检查锁漏洞)
-
volatile能解决可见性和有序性,但不能修复i++这种复合操作的原子性
synchronized 怎么真正起作用?
它背后是 JVM 的监视器(Monitor)机制:每个 Java 对象都关联一个 Monitor,monitorenter 和 monitorexit 字节码控制进入/退出。一旦某个线程拿到锁,其他线程只能排队等待。
- 修饰实例方法 → 锁的是
this对象 - 修饰静态方法 → 锁的是
ClassName.class - 修饰代码块 → 可指定任意对象作锁,更灵活,也更易避免锁粒度过大
- 支持可重入:同一线程可重复获取同一把锁,不会死锁
- 自动释放:无论正常结束还是抛异常,锁都会释放(这点比
ReentrantLock更省心)
用 AtomicInteger 替代锁,靠谱吗?
靠谱,但只适用于“单一变量的简单操作”。它底层靠 CPU 的 CAS(Compare-And-Swap)指令实现无锁并发,比如 incrementAndGet() 是原子的,不会丢更新。
家电公司网站源码是一个以米拓为核心进行开发的家电商城网站模板,程序采用metinfo5.3.9 UTF8进行编码,软件包含完整栏目与数据。安装方法:解压上传到空间,访问域名进行安装,安装好后,到后台-安全与效率-数据备份还原,恢复好数据后到设置-基本信息和外观-电脑把网站名称什么的改为自己的即可。默认后台账号:admin 密码:132456注意:如本地测试中127.0.0.1无法正常使用,请换成l
立即学习“Java免费学习笔记(深入)”;
- 优势:无锁、无上下文切换开销,高并发低竞争场景性能明显优于
synchronized - 局限:无法用于多变量协同逻辑(如“先查余额,够才扣款”这种两步操作),CAS 会失败重试,高竞争下可能自旋耗 CPU
- 别误用:
volatile int count+count++仍是线程不安全的 ——volatile不保原子性
真正难的从来不是“怎么加锁”,而是判断哪些共享状态需要保护、锁的范围是否过宽、有没有隐式共享(比如传入的集合参数被多个线程共用)。线程安全问题往往在压测或上线后才暴露,因为竞态条件依赖于线程调度的偶然性 —— 这也正是它最危险的地方。










