3. Java 后端开发常见锁机制问题
以下是几个与 Java 后端开发 相关的面试问题和 锁机制 的相关表格,帮助更好地理解常见的锁类型和应用场景。
3.1 Java 中的锁类型
锁类型 |
描述 |
常见实现类 |
适用场景 |
Synchronized |
Java 的内置锁,每个对象都有一个监视器锁,可以防止并发冲突。 |
synchronized 关键字 |
对方法或代码块加锁,单线程中同步执行 |
ReentrantLock |
可重入锁,允许更灵活的锁定机制,比 synchronized 更加强大 |
java.util.concurrent.locks.ReentrantLock |
需要更细粒度控制的多线程环境 |
ReadWriteLock |
读写锁,允许多个读线程同时访问,写线程独占资源 |
java.util.concurrent.locks.ReadWriteLock |
读多写少的场景,提高读取并发性能 |
StampedLock |
高效的读写锁,优化了大量的读操作,通过版本戳机制降低开销 |
java.util.concurrent.locks.StampedLock |
适用于高并发环境中的读操作,较少写操作 |
Semaphore |
信号量,用于控制对共享资源的访问数量 |
java.util.concurrent.Semaphore |
限制资源池的大小,控制并发数 |
CountDownLatch |
计数器,用于控制多个线程互相等待,直到一个条件满足 |
java.util.concurrent.CountDownLatch |
线程协调与等待,适用于任务结束等待 |
CyclicBarrier |
循环栅栏,用于协调多个线程在某一时刻同时开始执行 |
java.util.concurrent.CyclicBarrier |
多线程的阶段性执行协调 |
3.2 数据库锁与 Java 锁的区别
特性 |
数据库锁 |
Java 锁 |
粒度 |
行锁、表锁、页锁等,通常是数据库事务层面上的控制 |
锁定代码块、方法、对象,控制程序内存中的线程竞争 |
锁的获取方式 |
数据库通过事务隔离级别和锁机制(如 SELECT FOR UPDATE )加锁 |
通过 synchronized 、ReentrantLock 等实现同步 |
并发性能 |
行锁并发性能较高,表锁较低 |
ReentrantLock 提供更多灵活性,synchronized 性能较差但简单易用 |
使用场景 |
数据库访问层,控制数据库中的数据一致性与隔离性 |
代码执行层,控制多线程并发访问共享资源 |
死锁风险 |
数据库死锁可能发生,需依赖事务回滚机制 |
Java 锁死锁发生时会导致线程永久等待,需要开发者手动避免 |
事务支持 |
强事务支持,通常由数据库管理事务 |
事务支持需要通过外部框架(如 Spring)结合实现 |
4. Java 中的锁与并发控制的高级问题
问题 |
描述 |
解答要点 |
如何避免死锁 |
通过多线程的死锁问题,如何避免死锁的发生 |
避免嵌套锁、锁顺序、使用 tryLock 等方式避免 |
什么是乐观锁与悲观锁 |
介绍并发控制中的两种方式:悲观锁和乐观锁 |
悲观锁:SELECT FOR UPDATE ;乐观锁:基于版本号的控制 |
锁的竞争与上下文切换 |
锁竞争引起的性能问题,如何优化 |
减少锁的粒度、减少锁持有时间、使用无锁算法 |
什么是分布式锁?如何实现? |
在分布式环境中,如何确保数据的一致性与锁控制 |
使用 Redis、ZooKeeper 等实现分布式锁 |
如何使用 ReentrantLock 实现公平锁 |
如何确保多线程环境中的公平性,避免线程饥饿 |
使用 ReentrantLock 提供公平锁的构造函数 |
这些表格提供了多维度的比较和解答,帮助您在面试中全面理解和应用不同的锁机制和并发控制策略,尤其在 Java 后端开发中会涉及到这些问题。
锁类型 |
锁粒度 |
并发性 |
锁定范围 |
事务隔离性 |
描述 |
行锁 |
最细粒度(锁定单行) |
高并发 |
锁定特定数据行 |
提供较高的事务隔离性,通常支持 Serializable 和 Repeatable Read |
锁定表中的单行数据,允许并发事务操作不同的行,但会增加锁竞争。适合高并发写入操作。 |
间隙锁 |
锁定行与行之间的空隙(范围) |
中等并发 |
锁定两个索引值之间的“空隙” |
避免“幻读”现象,保证事务一致性。对插入操作有较强的隔离性。 |
锁定一个范围(空隙),防止其他事务在该间隙插入数据,从而避免幻读,但不会锁定实际的行数据。 |
临键锁 |
锁定键值范围 |
中等并发 |
锁定特定的键值范围 |
提供类似于行锁的隔离性,但范围较大,常见于范围查询或索引范围的保护。 |
锁定某个键值范围,用于防止其他事务在此范围内插入或修改数据,通常用于范围查询的场景。 |
表锁 |
粗粒度(锁定整表) |
低并发 |
锁定整个表 |
提供较低的隔离性,通常用于不需要高并发的全表操作。 |
锁定整个表,所有事务都无法访问该表的数据,适用于全表操作如备份、清理等。性能较差。 |
意向锁 |
由行锁或表锁组合成的锁粒度 |
不直接影响并发性 |
锁定事务意图的粒度 |
不直接影响事务隔离性,主要用于协调多粒度锁。 |
用于表示事务希望在更低粒度(如行锁)上加锁的意图,确保高粒度锁和细粒度锁不会冲突。 |