并发编程中常见的锁有哪几种?
1 个回答
不必太张扬,是花自然香。ketty## 作用 并发编程中的锁用于保证多个线程访问共享资源时的线程安全,避免数据竞争、可见性和原子性问题。根据不同分类标准,常见锁可以分为以下几类。 ## 原理与分类 ### 1. 悲观锁与乐观锁 - **悲观锁** - 认为并发冲突很容易发生,因此操作数据前先加锁。 - 其他线程必须等待锁释放后才能访问。 - 适合写多读少、冲突频繁的场景。 - 典型实现:`synchronized`、`ReentrantLock`、数据库 `SELECT ... FOR UPDATE`。 - **乐观锁** - 认为大多数情况下不会发生冲突,操作时不先加锁。 - 提交更新时通过版本号或 CAS 判断数据是否被其他线程修改。 - 如果冲突,则更新失败并重试。 - 适合读多写少、冲突较少的场景。 - 典型实现:数据库 `version` 字段、`AtomicInteger`、CAS。 ### 2. 公平锁与非公平锁 - **公平锁** - 多个线程按照申请锁的先后顺序获取锁。 - 优点是不会产生线程饥饿。 - 缺点是需要维护等待队列,性能通常较低。 - **非公平锁** - 线程获取锁时不一定按申请顺序,可能直接尝试抢占锁。 - 优点是吞吐率较高。 - 缺点是极端情况下部分线程可能长时间获取不到锁。 ### 3. 可重入锁与不可重入锁 - **可重入锁** - 同一个线程已经获得锁后,可以再次进入由同一把锁保护的代码。 - 可避免同线程重复加锁造成死锁。 - 典型实现:`synchronized`、`ReentrantLock`。 - **不可重入锁** - 线程获得锁后,如果再次请求同一把锁,也可能被阻塞。 - 使用不当时容易造成死锁。 ### 4. 自旋锁与阻塞锁 - **自旋锁** - 线程获取锁失败后不立即阻塞,而是循环尝试获取锁。 - 适合锁持有时间很短、临界区执行很快的场景。 - 优点是减少线程阻塞和唤醒的开销。 - 缺点是竞争激烈时会浪费 CPU。 - **阻塞锁** - 获取锁失败后线程进入阻塞状态,由系统在锁释放后唤醒。 - 适合锁持有时间较长的场景,可避免空转消耗 CPU。 ### 5. 偏向锁、轻量级锁与重量级锁 这是 Java `synchronized` 在不同竞争状态下常见的锁升级形式: - **偏向锁** - 在基本没有竞争时,锁偏向第一个获取它的线程。 - 同一线程再次进入同步块时不需要额外同步操作,开销较低。 - **轻量级锁** - 当出现多个线程交替访问时,偏向锁会撤销并升级为轻量级锁。 - 通常通过 CAS 尝试获取锁,适合竞争不激烈、锁占用时间短的情况。 - **重量级锁 - 当竞争激烈、CAS 自旋仍无法获取锁时,可能升级为重量级锁。 - 获取不到锁的线程会被阻塞,涉及操作系统级别的线程调度,开销较大。发布于 2026-10-25 14:25 •IP属地 云南举报评论收藏
公众号进入网站体验更佳

