同步与内存模型:synchronized/volatile/Lock、JMM 与可见性/有序性
大约 3 分钟
同步与内存模型:synchronized/volatile/Lock、JMM 与可见性/有序性
新手一屏速览
- JMM 的核心是 happens-before:写→读建立可见性与有序性保障
- volatile 只提供可见性与有序性(禁止重排序),不保证复合操作原子性
- 读多写少选读写锁/StampedLock;临界区短小优先 synchronized(简洁且 JVM 优化好)
1. JMM 基础与 happens-before
- 程序次序规则、监视器锁规则、volatile 规则、线程启动/终止规则、传递性
- 理解“何时对其他线程可见”,指导同步原语选型
2. volatile 与原子性
volatile boolean stop = false;
while (!stop) { /* ... */ }- 适用于标志位、一次写多次读;不适合自增/复合读写(需原子操作/锁)
3. synchronized 与 Lock
- synchronized 简洁、可重入、遇异常自动释放;JIT 对轻量级锁/偏向锁优化
- Lock 提供可定时/可中断/条件队列;ReentrantLock 与 Condition 适合复杂同步
4. 读写锁与 StampedLock
最近建一些几十个工作内推群,各大城市都有,群里目前已经收集了很多内推岗位,大厂、中厂、小厂、外包都有。 欢迎HR、开发、测试、运维和产品加入。

扫描下方微信,备注:网站+所在城市,即可拉你进工作内推群。

- ReadWriteLock 提升读多写少场景吞吐;StampedLock 降低写锁竞争并提供乐观读
- 乐观读需校验戳,失败则退化为悲观读
5. 常见误区与基准
- 双重检查锁定需使用 volatile;错误发布对象可能导致不可见
- 在临界区做阻塞 IO;在锁内调用外部不受控代码;锁粒度过大/过细
6. 练习
- 实现线程安全的懒加载单例(DCL+volatile),并加压校验可见性
- 为读多写少的缓存用 ReadWriteLock 与 StampedLock 两版实现,基准比较
示例代码(可直接复制运行)
示例一:volatile 可见性与停止信号
import java.util.concurrent.TimeUnit;
public class VolatileFlag {
private volatile boolean stop = false; // 可见性与有序性
public void work() {
while (!stop) { /* do work */ }
System.out.println("stopped");
}
public void requestStop() { stop = true; }
public static void main(String[] args) throws Exception {
VolatileFlag v = new VolatileFlag();
Thread t = new Thread(v::work);
t.start();
TimeUnit.MILLISECONDS.sleep(200);
v.requestStop();
t.join();
}
}示例二:synchronized 保障复合操作原子性
public class SyncCounter {
private int x = 0;
public synchronized void inc(){ x++; } // 原子性 + 可见性
public synchronized int get(){ return x; } // 可见性
public static void main(String[] args) throws Exception {
SyncCounter c = new SyncCounter();
Thread t1 = new Thread(() -> { for(int i=0;i<100000;i++) c.inc(); });
Thread t2 = new Thread(() -> { for(int i=0;i<100000;i++) c.inc(); });
t1.start(); t2.start(); t1.join(); t2.join();
System.out.println(c.get());
}
}示例三:ReentrantLock 与条件队列
import java.util.concurrent.locks.*;
import java.util.*;
public class BoundedBuffer<E> {
private final Queue<E> q = new ArrayDeque<>();
private final int cap;
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
public BoundedBuffer(int cap){ this.cap = cap; }
public void put(E e) throws InterruptedException {
lock.lock();
try {
while (q.size() == cap) notFull.await();
q.add(e);
notEmpty.signal();
} finally { lock.unlock(); }
}
public E take() throws InterruptedException {
lock.lock();
try {
while (q.isEmpty()) notEmpty.await();
E e = q.remove();
notFull.signal();
return e;
} finally { lock.unlock(); }
}
public static void main(String[] args) throws Exception {
BoundedBuffer<Integer> b = new BoundedBuffer<>(2);
Thread c = new Thread(() -> {
try { for(int i=0;i<5;i++) { b.put(i); System.out.println("put "+i); } }
catch (InterruptedException ignored) {}
});
Thread d = new Thread(() -> {
try { for(int i=0;i<5;i++) System.out.println("take "+b.take()); }
catch (InterruptedException ignored) {}
});
c.start(); d.start(); c.join(); d.join();
}
}示例四:ReadWriteLock 读多写少
import java.util.concurrent.locks.*;
import java.util.*;
public class RWCache<K,V> {
private final Map<K,V> m = new HashMap<>();
private final ReadWriteLock rw = new ReentrantReadWriteLock();
public V get(K k){
rw.readLock().lock();
try { return m.get(k); }
finally { rw.readLock().unlock(); }
}
public void put(K k, V v){
rw.writeLock().lock();
try { m.put(k, v); }
finally { rw.writeLock().unlock(); }
}
}示例五:StampedLock 乐观读
import java.util.concurrent.locks.StampedLock;
import java.util.*;
public class StampedCache<K,V> {
private final Map<K,V> m = new HashMap<>();
private final StampedLock sl = new StampedLock();
public V get(K k){
long st = sl.tryOptimisticRead();
V v = m.get(k);
if (!sl.validate(st)) {
long rs = sl.readLock();
try { v = m.get(k); }
finally { sl.unlockRead(rs); }
}
return v;
}
public void put(K k, V v){
long ws = sl.writeLock();
try { m.put(k, v); }
finally { sl.unlockWrite(ws); }
}
}示例六:双重检查锁定(DCL)+ volatile 单例
public class DCLSingleton {
private static volatile DCLSingleton INSTANCE; // 防止指令重排
private DCLSingleton(){}
public static DCLSingleton getInstance(){
DCLSingleton local = INSTANCE;
if (local == null) {
synchronized (DCLSingleton.class) {
local = INSTANCE;
if (local == null) {
local = new DCLSingleton();
INSTANCE = local;
}
}
}
return local;
}
public static void main(String[] args){
System.out.println(DCLSingleton.getInstance());
}
}