当前位置: 首页 > news >正文

锁原理和使用

在 Java 和数据库开发中,不同类型的锁被广泛应用来确保数据一致性和线程安全。以下是常用锁的分类及其实现原理详解,并提供了相应的示例。


1. 公平锁和非公平锁

  • 公平锁:线程按请求顺序获取锁,避免“插队”。
  • 非公平锁:允许线程在队列中“插队”,可能导致部分线程长时间等待。

实现方式ReentrantLock 支持公平和非公平锁,默认是非公平锁。

// 公平锁
ReentrantLock fairLock = new ReentrantLock(true);
// 非公平锁
ReentrantLock nonFairLock = new ReentrantLock(false);

2. 可重入锁

可重入锁允许同一线程多次获取同一锁,防止因自己再次获取锁而导致死锁。ReentrantLocksynchronized 都是可重入锁。

public class ReentrantExample {public synchronized void methodA() {methodB(); // 当前线程可以再次进入}public synchronized void methodB() {// 逻辑代码}
}

3. 递归锁

递归锁允许线程在持有锁的情况下递归调用获取该锁。它是可重入锁的实现方式之一。ReentrantLock 是递归锁的典型实现。


4. 自旋锁

自旋锁在等待获取锁时,不立即阻塞线程,而是通过循环尝试。适合锁的持有时间较短的场景,减少了上下文切换的开销。

public class SpinLock {private AtomicReference<Thread> owner = new AtomicReference<>();public void lock() {Thread current = Thread.currentThread();while (!owner.compareAndSet(null, current)) {// 自旋等待}}public void unlock() {Thread current = Thread.currentThread();owner.compareAndSet(current, null);}
}

5. 读写锁

读写锁分为读锁和写锁,多个线程可以同时读取数据,但写操作是独占的。典型实现是 ReentrantReadWriteLock

ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
lock.readLock().lock();
try {// 读取操作
} finally {lock.readLock().unlock();
}lock.writeLock().lock();
try {// 写入操作
} finally {lock.writeLock().unlock();
}

6. 悲观锁和乐观锁

  • 悲观锁:假定并发冲突频繁,数据操作前即上锁,如数据库的 SELECT ... FOR UPDATE
  • 乐观锁:假定并发冲突较少,通过版本号等机制在提交时验证数据是否被修改。
// 乐观锁示例
public void updateWithOptimisticLock(int version) {// 更新时检查 version 是否相同String sql = "UPDATE table SET column = ? WHERE version = ?";
}

7. 行锁和表锁

  • 行锁:锁定特定行,如 InnoDB 支持行锁。
  • 表锁:锁定整个表,MyISAM 仅支持表锁。

行锁更适合高并发写操作,表锁适合大量读操作的场景。


8. 排它锁和共享锁

  • 排它锁(独占锁):同一时间只允许一个事务访问数据。
  • 共享锁:允许多个事务同时读取数据,但不允许写入。

SELECT ... LOCK IN SHARE MODE 创建共享锁。


9. 死锁

死锁是指两个或多个线程相互持有对方需要的锁,导致永久等待。避免死锁的方法包括:

  • 保持锁定顺序一致
  • 使用定时锁,尝试锁超时失败
  • 减少锁的持有时间

10. 分布式锁

分布式锁用于确保分布式系统中资源的独占性。Redis 和 Zookeeper 是常用的实现工具。典型的 Redis 分布式锁示例:

// Redis分布式锁示例
String lockKey = "resource_lock";
String requestId = UUID.randomUUID().toString();// 加锁
boolean lock = redis.set(lockKey, requestId, "NX", "PX", 30000); // NX:不存在时设置, PX:设置超时// 解锁
if (requestId.equals(redis.get(lockKey))) {redis.del(lockKey);
}

11. AQS(AbstractQueuedSynchronizer)

AQS 是 Java 提供的一个用于构建锁和同步器的底层框架,基于一个先进先出的队列来管理锁的获取和释放。ReentrantLockSemaphoreCountDownLatch 等类均基于 AQS 实现。


12. Synchronized 原理

synchronized 是 Java 的内置锁,通过对象监视器实现。其底层是基于 Monitor 锁机制,每个对象包含一个 Monitor,实现方法包括:

  • 对象头的 Mark Word:记录线程的锁定状态。
  • 锁升级机制:从偏向锁、轻量级锁到重量级锁,以适应不同并发量的场景。

示例

public synchronized void syncMethod() {// 方法体
}

13. 锁的使用示例

// 使用ReentrantLock可重入锁示例
public class ReentrantLockExample {private final ReentrantLock lock = new ReentrantLock();public void performTask() {lock.lock();try {System.out.println("任务执行中...");} finally {lock.unlock();}}
}// 使用Synchronized实现同步块
public class SynchronizedExample {public void synchronizedTask() {synchronized (this) {System.out.println("同步任务执行中...");}}
}

总结

在高并发编程和分布式系统中,不同锁的特性决定了其适用场景。了解各种锁的原理和使用方法,能够帮助开发者在不同场景中选择合适的锁机制,从而实现线程安全并优化性能。


http://www.mrgr.cn/news/64170.html

相关文章:

  • selinux和防火墙
  • STM32CUBEMX安富莱STM32-V6开发板使用FMC驱动SDRAM芯片MT48LC4M32B2TG
  • 20241102编译Rockchip原厂的RK3566平台的Buildroot【repo模式】
  • ffmpeg+vue2
  • Mybatis-plus入门教程
  • C/C++ 每日一练:二叉树的先序遍历
  • Python自动化运维:技能掌握与快速入门指南
  • 绿色积分如何结合商家联盟?打造线上线下消费生态
  • MMSegmentation测试阶段推理速度非常慢的一种可能原因
  • 优先级队列(PriorityQueue)
  • Visual Studio 2019下载安装使用教程
  • Php实现钉钉OA一级审批,二级审批
  • 河南省教育厅办公室关于举办2024年河南省高等职业教育技能大赛的通知
  • electron + vue 打包完成后,运行提示 electrion-updater 不存在
  • 最小支撑树MST
  • 数据结构-复杂度
  • phcharm贪吃蛇小游戏后续一(代码1,2,3前文已发)
  • CesiumJS 案例 P18:检测文本、删除所有文本、隐藏与显示文本、改变文本
  • 二维码中怎么存入文件?文件二维码活码的3步制作技巧
  • CAD图纸防泄密|哪些措施可以加密公司图纸?五个宝藏方法分享,2024必读!
  • 无人机维护保养、部件修理更换技术详解
  • Python 列表的定义语法
  • 【毫米波雷达(四)】车载毫米波雷达下线EOL标定流程
  • 【VUE+DRF】案例升级
  • 国产服务器部署1.获取银河麒麟V10服务器。首先挂gpt数据盘
  • Apache-Seata 拯救分布式系统数据一致性的开源神器