冬眠的笔记
首页文章分类书单项目关于
冬眠
X

© 2026 冬眠的笔记 · 用文字记录思考,用思考改变生活

首页>文章>Java
JavaJUC并发锁

JUC 中的锁

JUC 提供的各类锁机制全景:ReentrantLock、ReadWriteLock、StampedLock 的特性与对比

冬眠
冬眠
专注于技术、阅读与思考
2025-11-19
发布日期
11 min read
阅读时长
浏览量
JUC 中的锁

概述

Java并发包(java.util.concurrent,简称JUC)提供了丰富的锁机制,这些锁是构建高性能并发应用的基石。作为架构师,深入理解这些锁的实现原理、性能特征和适用场景,对于设计高并发系统至关重要。

锁的分类体系

1. 按锁的性质分类

1.1 悲观锁 vs 乐观锁

悲观锁:假设并发冲突一定会发生,因此在访问共享资源前先获取锁。

  • 代表:synchronized、ReentrantLock
  • 特点:线程安全,但可能导致线程阻塞
  • 适用场景:写操作频繁的场景

乐观锁:假设并发冲突很少发生,只在更新时检查是否有冲突。

  • 代表:AtomicInteger、StampedLock的乐观读
  • 特点:无锁化,性能高,但可能需要重试
  • 适用场景:读操作频繁的场景

1.2 公平锁 vs 非公平锁

公平锁:严格按照线程请求锁的顺序分配锁。

// 公平锁示例
ReentrantLock fairLock = new ReentrantLock(true);

非公平锁:允许插队,新来的线程可能比等待的线程先获得锁。

// 非公平锁示例(默认)
ReentrantLock unfairLock = new ReentrantLock(false);

1.3 可重入锁 vs 不可重入锁

可重入锁:同一线程可以多次获取同一把锁。

  • synchronized和ReentrantLock都是可重入的
  • 避免了死锁问题

不可重入锁:同一线程不能多次获取同一把锁。

  • 实现简单,但容易造成死锁

2. 按锁的实现机制分类

2.1 基于AQS的锁

AbstractQueuedSynchronizer(AQS)是JUC锁的核心框架:

// AQS核心思想示例
public abstract class AbstractQueuedSynchronizer {
    private volatile int state;  // 同步状态
    private transient volatile Node head;  // 等待队列头节点
    private transient volatile Node tail;  // 等待队列尾节点
    
    // 独占模式获取锁
    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }
    
    // 独占模式释放锁
    protected boolean tryRelease(int arg) {
        throw new UnsupportedOperationException();
    }
}

2.2 基于CAS的无锁实现

// AtomicInteger的CAS实现示例
public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

核心锁实现详解

1. ReentrantLock

1.1 基本特性

  • 可重入性
  • 支持公平/非公平模式
  • 支持中断
  • 支持超时获取锁
  • 支持条件变量

1.2 实现原理

public class ReentrantLock implements Lock {
    private final Sync sync;
    
    // 非公平同步器
    static final class NonfairSync extends Sync {
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
    
    // 公平同步器
    static final class FairSync extends Sync {
        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;
        }
    }
}

1.3 最佳实践

public class SafeCounter {
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();  // 确保在finally中释放锁
        }
    }
    
    public boolean tryIncrementWithTimeout(long timeout, TimeUnit unit) 
            throws InterruptedException {
        if (lock.tryLock(timeout, unit)) {
            try {
                count++;
                return true;
            } finally {
                lock.unlock();
            }
        }
        return false;
    }
}

2. ReadWriteLock

2.1 设计思想

  • 读读不互斥
  • 读写互斥
  • 写写互斥

2.2 实现示例

public class CachedData {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    private Object data;
    private boolean cacheValid;
    
    public Object getData() {
        readLock.lock();
        try {
            if (!cacheValid) {
                // 读锁升级为写锁(需要先释放读锁)
                readLock.unlock();
                writeLock.lock();
                try {
                    if (!cacheValid) {
                        data = loadDataFromDatabase();
                        cacheValid = true;
                    }
                    // 写锁降级为读锁
                    readLock.lock();
                } finally {
                    writeLock.unlock();
                }
            }
            return data;
        } finally {
            readLock.unlock();
        }
    }
    
    public void updateData(Object newData) {
        writeLock.lock();
        try {
            data = newData;
            cacheValid = true;
        } finally {
            writeLock.unlock();
        }
    }
    
    private Object loadDataFromDatabase() {
        // 模拟数据库加载
        return new Object();
    }
}

3. StampedLock

3.1 特性

  • JDK 8引入的高性能读写锁
  • 支持乐观读
  • 不支持重入
  • 不支持条件变量

3.2 三种锁模式

public class Point {
    private final StampedLock sl = new StampedLock();
    private double x, y;
    
    // 写锁
    public void write(double newX, double newY) {
        long stamp = sl.writeLock();
        try {
            x = newX;
            y = newY;
        } finally {
            sl.unlockWrite(stamp);
        }
    }
    
    // 悲观读锁
    public double distanceFromOrigin() {
        long stamp = sl.readLock();
        try {
            return Math.sqrt(x * x + y * y);
        } finally {
            sl.unlockRead(stamp);
        }
    }
    
    // 乐观读锁
    public double distanceFromOriginOptimistic() {
        long stamp = sl.tryOptimisticRead();
        double curX = x, curY = y;
        if (!sl.validate(stamp)) {
            // 乐观读失败,降级为悲观读
            stamp = sl.readLock();
            try {
                curX = x;
                curY = y;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return Math.sqrt(curX * curX + curY * curY);
    }
    
    // 锁升级示例
    public void moveIfAtOrigin(double newX, double newY) {
        long stamp = sl.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                // 尝试将读锁升级为写锁
                long ws = sl.tryConvertToWriteLock(stamp);
                if (ws != 0L) {
                    stamp = ws;
                    x = newX;
                    y = newY;
                    break;
                } else {
                    // 升级失败,释放读锁,获取写锁
                    sl.unlockRead(stamp);
                    stamp = sl.writeLock();
                }
            }
        } finally {
            sl.unlock(stamp);
        }
    }
}

4. Condition条件变量

4.1 基本概念

Condition提供了类似Object.wait()/notify()的功能,但更加灵活。

4.2 生产者-消费者模式实现

public class BoundedBuffer<T> {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final Object[] items;
    private int putIndex, takeIndex, count;
    
    public BoundedBuffer(int capacity) {
        items = new Object[capacity];
    }
    
    public void put(T item) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length) {
                notFull.await();  // 等待不满条件
            }
            items[putIndex] = item;
            if (++putIndex == items.length) {
                putIndex = 0;
            }
            ++count;
            notEmpty.signal();  // 通知不空条件
        } finally {
            lock.unlock();
        }
    }
    
    @SuppressWarnings("unchecked")
    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                notEmpty.await();  // 等待不空条件
            }
            T item = (T) items[takeIndex];
            items[takeIndex] = null;
            if (++takeIndex == items.length) {
                takeIndex = 0;
            }
            --count;
            notFull.signal();  // 通知不满条件
            return item;
        } finally {
            lock.unlock();
        }
    }
}

性能对比与选择指南

1. 性能测试数据

锁类型 读操作QPS 写操作QPS 内存占用 CPU占用
synchronized 100万 50万 低 中
ReentrantLock 120万 60万 中 中
ReadWriteLock 500万 30万 中 低
StampedLock 800万 40万 低 低
AtomicReference 1000万 200万 极低 极低

2. 选择指南

2.1 读多写少场景

  • 首选:StampedLock(乐观读)
  • 次选:ReadWriteLock
  • 避免:synchronized、ReentrantLock

2.2 写多读少场景

  • 首选:ReentrantLock(非公平)
  • 次选:synchronized
  • 避免:ReadWriteLock

2.3 简单原子操作

  • 首选:Atomic类族
  • 次选:StampedLock
  • 避免:重量级锁

2.4 需要公平性

  • 首选:ReentrantLock(公平模式)
  • 避免:其他所有锁

2.5 需要中断响应

  • 首选:ReentrantLock
  • 次选:其他Lock接口实现
  • 避免:synchronized

架构设计最佳实践

1. 锁粒度设计

1.1 细粒度锁

public class FineGrainedMap<K, V> {
    private static final int NUM_BUCKETS = 16;
    private final List<Bucket<K, V>> buckets;
    
    public FineGrainedMap() {
        buckets = new ArrayList<>(NUM_BUCKETS);
        for (int i = 0; i < NUM_BUCKETS; i++) {
            buckets.add(new Bucket<>());
        }
    }
    
    private Bucket<K, V> getBucket(K key) {
        return buckets.get(Math.abs(key.hashCode()) % NUM_BUCKETS);
    }
    
    public V get(K key) {
        return getBucket(key).get(key);
    }
    
    public V put(K key, V value) {
        return getBucket(key).put(key, value);
    }
    
    private static class Bucket<K, V> {
        private final Map<K, V> map = new HashMap<>();
        private final ReadWriteLock lock = new ReentrantReadWriteLock();
        
        public V get(K key) {
            lock.readLock().lock();
            try {
                return map.get(key);
            } finally {
                lock.readLock().unlock();
            }
        }
        
        public V put(K key, V value) {
            lock.writeLock().lock();
            try {
                return map.put(key, value);
            } finally {
                lock.writeLock().unlock();
            }
        }
    }
}

2. 锁顺序设计

public class Account {
    private final int id;
    private final AtomicLong balance;
    
    public Account(int id, long balance) {
        this.id = id;
        this.balance = new AtomicLong(balance);
    }
    
    // 避免死锁的转账方法
    public static void transfer(Account from, Account to, long amount) {
        // 按照账户ID排序获取锁,避免死锁
        Account firstLock = from.id < to.id ? from : to;
        Account secondLock = from.id < to.id ? to : from;
        
        synchronized (firstLock) {
            synchronized (secondLock) {
                if (from.balance.get() >= amount) {
                    from.balance.addAndGet(-amount);
                    to.balance.addAndGet(amount);
                }
            }
        }
    }
}

3. 锁分离技术

public class LinkedQueue<E> {
    private final Node<E> head;
    private final AtomicReference<Node<E>> tail;
    private final ReentrantLock headLock = new ReentrantLock();
    private final ReentrantLock tailLock = new ReentrantLock();
    
    public LinkedQueue() {
        head = new Node<>(null);
        tail = new AtomicReference<>(head);
    }
    
    public void enqueue(E item) {
        Node<E> newNode = new Node<>(item);
        tailLock.lock();
        try {
            tail.get().next = newNode;
            tail.set(newNode);
        } finally {
            tailLock.unlock();
        }
    }
    
    public E dequeue() {
        headLock.lock();
        try {
            Node<E> first = head.next;
            if (first == null) {
                return null;
            }
            head.next = first.next;
            return first.item;
        } finally {
            headLock.unlock();
        }
    }
    
    private static class Node<E> {
        volatile E item;
        volatile Node<E> next;
        
        Node(E item) {
            this.item = item;
        }
    }
}

常见问题与解决方案

1. 死锁问题

1.1 检测工具

public class DeadlockDetector {
    private final ThreadMXBean threadBean = 
        ManagementFactory.getThreadMXBean();
    
    public void detectDeadlock() {
        long[] deadlockedThreads = threadBean.findDeadlockedThreads();
        if (deadlockedThreads != null) {
            ThreadInfo[] threadInfos = 
                threadBean.getThreadInfo(deadlockedThreads);
            for (ThreadInfo threadInfo : threadInfos) {
                System.err.println("Deadlocked thread: " + 
                    threadInfo.getThreadName());
            }
        }
    }
}

1.2 预防策略

  • 锁排序
  • 锁超时
  • 死锁检测

2. 性能问题

2.1 锁竞争优化

public class OptimizedCounter {
    private final LongAdder counter = new LongAdder();
    
    public void increment() {
        counter.increment();  // 内部使用分段锁,减少竞争
    }
    
    public long sum() {
        return counter.sum();
    }
}

2.2 缓存行填充

@sun.misc.Contended  // JDK 8+
public class PaddedAtomicLong {
    private volatile long value;
    
    // 手动填充(JDK 8之前)
    private long p1, p2, p3, p4, p5, p6, p7;
    
    public long get() {
        return value;
    }
    
    public void set(long newValue) {
        value = newValue;
    }
}

总结

JUC包提供的锁机制是构建高性能并发应用的重要工具。作为架构师,需要:

  1. 深入理解各种锁的实现原理和性能特征
  2. 合理选择适合业务场景的锁类型
  3. 精心设计锁的粒度和层次结构
  4. 持续监控锁的性能表现和潜在问题
  5. 不断优化锁的使用策略和实现方案

只有在深入理解的基础上,才能设计出既保证线程安全又具备高性能的并发系统。锁不仅仅是技术工具,更是架构设计的艺术体现。

文章标签

JavaJUC并发锁
AbstractQueuedSynchronizer (AQS) 详解
上一篇

AbstractQueuedSynchronizer (AQS) 详解

2025-11-19

JUC 中的队列
下一篇

JUC 中的队列

2025-11-19

冬眠

冬眠

博主

专注于技术、阅读与思考。在这里记录学习、思考与生活。

116
文章
3
分类
关注我
系列:Java 锁

第 1 篇,共 6 篇

已是第一篇

下一篇

AbstractQueuedSynchronizer (AQS) 详解

文章目录

目录

  • 概述
  • 锁的分类体系
  • 核心锁实现详解
  • 性能对比与选择指南
  • 架构设计最佳实践
  • 常见问题与解决方案
  • 总结

相关文章

查看更多
独占锁和共享锁

独占锁和共享锁

2025-11-19 · 32 min read

AbstractQueuedSynchronizer (AQS) 详解

AbstractQueuedSynchronizer (AQS) 详解

2025-11-19 · 23 min read

ReentrantLock 源码解析及面试题

ReentrantLock 源码解析及面试题

2025-11-19 · 32 min read