一、引言
锁是并发编程的基石,Java提供了丰富的锁机制来保证线程安全。本文将从JVM底层到应用层,全面剖析Java线程锁的核心原理与高级用法。
本文基于 JDK 17 源码分析,涉及大量底层实现细节,适合有一定并发编程基础的开发者。
二、synchronized 底层实现
2.1 对象头与 Mark Word
每个Java对象在内存中的布局包括对象头、实例数据和对齐填充。对象头中的 Mark Word 存储了锁状态信息:
1 2 3 4 5 6 7 8 9
| ┌─────────────────────────────────────────────────────┐ │ Mark Word (64bit) │ ├─────────────────────────────────────────────────────┤ │ 无锁状态: unused:25 | hash:31 | age:4 | biased:0 | 01 │ │ 偏向锁: thread:54 | epoch:2 | age:4 | biased:1 | 01 │ │ 轻量级锁: ptr_to_lock_record:62 | 00 │ │ 重量级锁: ptr_to_heavyweight_monitor:62 | 10 │ │ GC标记: 空 | 11 │ └─────────────────────────────────────────────────────┘
|
2.2 偏向锁原理
偏向锁适用于单线程访问场景,通过CAS将线程ID记录到对象头:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class BiasedLocking { if (!mark.is_biased_anonymously()) { if (mark.thread() == current_thread) { return true; } } if (CAS(mark.word(), expected, current_thread_id)) { return true; } revoke_bias(); }
|
偏向锁在 JDK 15 中被默认禁用(-XX:+UseBiasedLocking),因为现代应用中多线程竞争频繁,偏向锁撤销成本高。
2.3 轻量级锁与自旋
轻量级锁通过CAS自旋避免线程阻塞:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class LightweightLock { void lock(Object obj) { LockRecord record = new LockRecord(); record.displaced_header = obj.mark_word(); if (CAS(obj.mark_word(), record.displaced_header, record.ptr())) { return; } int spin_count = 0; while (spin_count < MAX_SPIN) { if (CAS(obj.mark_word(), record.displaced_header, record.ptr())) { return; } spin_count++; } inflate_to_heavyweight(obj); } }
|
2.4 重量级锁与 Monitor
重量级锁通过操作系统的互斥量实现,涉及用户态到内核态的切换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class ObjectMonitor { ObjectWaiter* _wait_set; ObjectWaiter* _entry_list; Thread* _owner; int _count; volatile int _recursions; void enter(Thread* self) { if (CAS(&_owner, NULL, self)) { return; } if (_owner == self) { _recursions++; return; } if (TrySpin(self)) { return; } ParkEvent* event = self->_ParkEvent; _entry_list.enqueue(self); event->park(); } }
|
三、AQS(AbstractQueuedSynchronizer)框架
3.1 AQS 核心数据结构
AQS 是 Java 并发包的基石,ReentrantLock、Semaphore、CountDownLatch 等都基于它实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer { private volatile int state; private transient volatile Node head; private transient volatile Node tail; static final class Node { static final Node SHARED = new Node(); static final Node EXCLUSIVE = null; volatile int waitStatus; volatile Node prev; volatile Node next; volatile Thread thread; Node nextWaiter; static final int CANCELLED = 1; static final int SIGNAL = -1; static final int CONDITION = -2; static final int PROPAGATE = -3; } }
|
3.2 独占锁获取流程
以 ReentrantLock 的公平锁为例,分析 acquire 流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
private Node addWaiter(Node mode) { Node node = new Node(mode); Node oldTail = tail; if (oldTail != null) { node.prev = oldTail; if (compareAndSetTail(oldTail, node)) { oldTail.next = node; return node; } } enq(node); return node; }
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node)) interrupted |= parkAndCheckInterrupt(); } } finally { if (failed) cancelAcquire(node); } }
|
3.3 锁释放与唤醒机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
private void unparkSuccessor(Node node) { int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread); }
|
四、ReentrantLock 源码分析
4.1 非公平锁实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| public class ReentrantLock implements Lock { private final Sync sync; static final class NonfairSync extends Sync { final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } abstract static class Sync extends AbstractQueuedSynchronizer { final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = (c == 0); if (free) setExclusiveOwnerThread(null); setState(c); return free; } } }
|
4.2 公平锁实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| static final class FairSync extends Sync { final void lock() { acquire(1); } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }
public final boolean hasQueuedPredecessors() { Node t = tail; Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
|
公平锁保证FIFO顺序,但性能较差;非公平锁允许插队,吞吐量更高。默认使用非公平锁。
五、读写锁 ReentrantReadWriteLock
5.1 状态设计
读写锁用一个int变量同时表示读锁和写锁状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class ReentrantReadWriteLock { static final int SHARED_SHIFT = 16; static final int SHARED_UNIT = (1 << SHARED_SHIFT); static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; static int sharedCount(int c) { return c >>> SHARED_SHIFT; } static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } abstract static class Sync extends AbstractQueuedSynchronizer { protected final int tryAcquireShared(int unused) { Thread current = Thread.currentThread(); int c = getState(); if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return -1; int r = sharedCount(c); if (r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) { if (r == 0) { firstReader = current; firstReaderHoldCount = 1; } else if (firstReader == current) { firstReaderHoldCount++; } else { HoldCounter rh = cachedHoldCounter; if (rh == null || rh.tid != getThreadId(current)) cachedHoldCounter = rh = readHolds.get(); rh.count++; } return 1; } return fullTryAcquireShared(current); } } }
|
5.2 锁降级
写锁可以降级为读锁,但读锁不能升级为写锁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class LockDowngradeExample { private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); private final Lock readLock = rwLock.readLock(); private final Lock writeLock = rwLock.writeLock(); public void processData() { writeLock.lock(); try { modifyData(); readLock.lock(); } finally { writeLock.unlock(); } try { readData(); } finally { readLock.unlock(); } } }
|
5.3 StampedLock 乐观读
JDK 8引入的 StampedLock 支持乐观读,性能优于读写锁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class StampedLockExample { private final StampedLock sl = new StampedLock(); private double x, y; public double distanceFromOrigin() { long stamp = sl.tryOptimisticRead(); double currentX = x; double currentY = y; if (!sl.validate(stamp)) { stamp = sl.readLock(); try { currentX = x; currentY = y; } finally { sl.unlockRead(stamp); } } return Math.sqrt(currentX * currentX + currentY * currentY); } public void move(double deltaX, double deltaY) { long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); } } }
|
StampedLock 不可重入,不支持 Condition,使用时需注意避免嵌套获取导致死锁。
六、Condition 条件队列
6.1 Condition 实现原理
Condition 基于 AQS 的条件队列实现,与 synchronized 的 wait/notify 机制类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| public class ConditionObject implements Condition { private transient Node firstWaiter; private transient Node lastWaiter; public final void await() throws InterruptedException { Node node = addConditionWaiter(); int savedState = fullyRelease(node); while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } acquireQueued(node, savedState, interruptMode); } public final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); } private void doSignal(Node first) { do { if ((firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null); } final boolean transferForSignal(Node node) { if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; Node p = enq(node); int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; } }
|
6.2 生产者-消费者实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public class BoundedBuffer<T> { private final Lock lock = new ReentrantLock(); private final Condition notFull = lock.newCondition(); private final Condition notEmpty = lock.newCondition(); private final Object[] items; private int putptr, takeptr, count; public BoundedBuffer(int capacity) { items = new Object[capacity]; } public void put(T x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; count++; notEmpty.signal(); } finally { lock.unlock(); } } @SuppressWarnings("unchecked") public T take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); T x = (T) items[takeptr]; items[takeptr] = null; if (++takeptr == items.length) takeptr = 0; count--; notFull.signal(); return x; } finally { lock.unlock(); } } }
|
七、死锁检测与预防
7.1 死锁的四个必要条件
- 互斥条件:资源一次只能被一个线程持有
- 持有并等待:线程持有资源的同时等待其他资源
- 不可剥夺:已持有的资源不能被强制释放
- 循环等待:线程之间形成环形等待链
7.2 使用 jstack 检测死锁
1 2 3 4 5
| jstack -l <pid> > thread_dump.txt
grep -A 20 "Found one Java-level deadlock" thread_dump.txt
|
7.3 使用 JConsole 检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class DeadlockDetector { private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); public void detectDeadlocks() { long[] threadIds = threadBean.findDeadlockedThreads(); if (threadIds != null) { ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadIds, true, true); for (ThreadInfo info : threadInfos) { System.out.println("Deadlock detected:"); System.out.println(" Thread: " + info.getThreadName()); System.out.println(" Blocked on: " + info.getLockName()); System.out.println(" Lock owner: " + info.getLockOwnerName()); } } } }
|
7.4 预防死锁策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| public class OrderedLockTransfer { private static final Object lock1 = new Object(); private static final Object lock2 = new Object(); public void transfer() { synchronized (lock1) { synchronized (lock2) { } } } }
public class TryLockExample { private final Lock lock1 = new ReentrantLock(); private final Lock lock2 = new ReentrantLock(); public void transfer() throws InterruptedException { while (true) { boolean gotLock1 = lock1.tryLock(100, TimeUnit.MILLISECONDS); boolean gotLock2 = lock2.tryLock(100, TimeUnit.MILLISECONDS); if (gotLock1 && gotLock2) { try { return; } finally { lock1.unlock(); lock2.unlock(); } } if (gotLock1) lock1.unlock(); if (gotLock2) lock2.unlock(); Thread.sleep(ThreadLocalRandom.current().nextInt(10, 100)); } } }
public class TimedLockTransfer { private final Lock lock = new ReentrantLock(); public boolean tryTransfer(long timeout, TimeUnit unit) throws InterruptedException { long deadline = System.nanoTime() + unit.toNanos(timeout); while (System.nanoTime() < deadline) { if (lock.tryLock(10, TimeUnit.MILLISECONDS)) { try { return true; } finally { lock.unlock(); } } } return false; } }
|
八、锁性能优化策略
8.1 减小锁粒度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class CoarseGrainedCache { private final Map<String, Object> cache = new HashMap<>(); public synchronized Object get(String key) { return cache.get(key); } public synchronized void put(String key, Object value) { cache.put(key, value); } }
public class FineGrainedCache { private static final int SEGMENTS = 16; private final Segment[] segments = new Segment[SEGMENTS]; private static class Segment { final Map<String, Object> map = new HashMap<>(); final ReentrantLock lock = new ReentrantLock(); } public Object get(String key) { Segment segment = segments[key.hashCode() & (SEGMENTS - 1)]; segment.lock.lock(); try { return segment.map.get(key); } finally { segment.lock.unlock(); } } }
|
8.2 锁分离
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class ReadWriteLockCache { private final Map<String, Object> cache = new HashMap<>(); private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); private final Lock readLock = rwLock.readLock(); private final Lock writeLock = rwLock.writeLock(); public Object get(String key) { readLock.lock(); try { return cache.get(key); } finally { readLock.unlock(); } } public void put(String key, Object value) { writeLock.lock(); try { cache.put(key, value); } finally { writeLock.unlock(); } } }
|
8.3 无锁编程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class LockFreeStack<E> { private final AtomicReference<Node<E>> top = new AtomicReference<>(); public void push(E item) { Node<E> newHead = new Node<>(item); Node<E> oldHead; do { oldHead = top.get(); newHead.next = oldHead; } while (!top.compareAndSet(oldHead, newHead)); } public E pop() { Node<E> oldHead; Node<E> newHead; do { oldHead = top.get(); if (oldHead == null) return null; newHead = oldHead.next; } while (!top.compareAndSet(oldHead, newHead)); return oldHead.item; } private static class Node<E> { final E item; Node<E> next; Node(E item) { this.item = item; } } }
|
九、实战:高性能并发缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| public class HighPerformanceCache<K, V> { private final ConcurrentHashMap<K, CacheEntry<V>> cache = new ConcurrentHashMap<>(); private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); private final DelayQueue<DelayedEntry<K>> expireQueue = new DelayQueue<>(); private final ScheduledExecutorService cleaner = Executors.newSingleThreadScheduledExecutor(); public HighPerformanceCache() { cleaner.scheduleAtFixedRate(this::cleanExpired, 1, 1, TimeUnit.SECONDS); } public V get(K key) { CacheEntry<V> entry = cache.get(key); if (entry == null) { return null; } if (entry.isExpired()) { cache.remove(key); return null; } entry.touch(); return entry.getValue(); } public void put(K key, V value, long ttl, TimeUnit unit) { CacheEntry<V> entry = new CacheEntry<>(value, ttl, unit); CacheEntry<V> existing = cache.putIfAbsent(key, entry); if (existing != null) { existing.update(value, ttl, unit); } else { expireQueue.offer(new DelayedEntry<>(key, ttl, unit)); } } public V computeIfAbsent(K key, Function<K, V> loader, long ttl, TimeUnit unit) { CacheEntry<V> entry = cache.get(key); if (entry != null && !entry.isExpired()) { return entry.getValue(); } rwLock.writeLock().lock(); try { entry = cache.get(key); if (entry != null && !entry.isExpired()) { return entry.getValue(); } V value = loader.apply(key); put(key, value, ttl, unit); return value; } finally { rwLock.writeLock().unlock(); } } private void cleanExpired() { List<DelayedEntry<K>> expired = new ArrayList<>(); expireQueue.drainTo(expired); for (DelayedEntry<K> entry : expired) { cache.remove(entry.getKey()); } } private static class CacheEntry<V> { private volatile V value; private volatile long expireTime; private volatile long lastAccessTime; CacheEntry(V value, long ttl, TimeUnit unit) { this.value = value; this.expireTime = System.nanoTime() + unit.toNanos(ttl); this.lastAccessTime = System.nanoTime(); } boolean isExpired() { return System.nanoTime() > expireTime; } void touch() { this.lastAccessTime = System.nanoTime(); } void update(V value, long ttl, TimeUnit unit) { this.value = value; this.expireTime = System.nanoTime() + unit.toNanos(ttl); } V getValue() { return value; } } }
|
十、总结
10.1 锁选择指南
| 场景 |
推荐锁 |
原因 |
| 低竞争,单线程访问 |
偏向锁(JDK 14前) |
零开销 |
| 低竞争,多线程 |
synchronized |
JVM自动优化 |
| 高竞争,需要公平性 |
公平ReentrantLock |
FIFO保证 |
| 高竞争,不需要公平 |
非公平ReentrantLock |
高吞吐 |
| 读多写少 |
ReentrantReadWriteLock |
读并发 |
| 读极多,偶尔写 |
StampedLock |
乐观读无锁 |
| 超时控制 |
ReentrantLock + tryLock |
避免死锁 |
10.2 最佳实践
- 减小锁粒度:只锁必要代码,减少临界区
- 避免锁嵌套:必须嵌套时固定顺序
- 使用tryLock:带超时,避免无限等待
- 锁分离:读写分离,提高并发度
- 无锁优先:考虑CAS、LongAdder等无锁方案
锁的选择没有银弹,需要根据具体场景权衡。低竞争场景 synchronized 性能最好(JVM优化),高竞争场景需要考虑锁分离或无锁方案。
参考资料
- OpenJDK AQS源码
- 《Java并发编程实战》- Brian Goetz
- 《Java并发编程的艺术》- 方腾飞
- Java LockSupport官方文档
- JEP 374: Disable biased locking
版权声明:本文为原创文章,转载请注明出处。
更新日志: