首页 > 编程语言 >Java中的乐观锁和悲观锁

Java中的乐观锁和悲观锁

时间:2024-11-20 10:29:11浏览次数:1  
标签:CAS Java 版本号 lock 乐观 int 线程 悲观 public

在多线程编程中,锁机制是确保数据一致性和线程安全的关键技术。悲观锁和乐观锁是两种常见的锁机制,它们在不同的场景下有着各自的优势和适用范围。

悲观锁和乐观锁的概念

悲观锁(Pessimistic Locking)假设在并发环境中会发生冲突,因此在访问共享资源时总是先加锁,确保在事务期间没有其他线程可以修改该资源。悲观锁在事务开始时就获取锁,直到事务结束时才释放锁。

乐观锁
乐观锁(Optimistic Locking)假设在并发环境中很少发生冲突,因此在访问共享资源时不立即加锁,而是等到真正需要修改资源时再检查是否有冲突。如果发现冲突,则采取补偿措施(如重试或回滚)。

1. 乐观锁 (Optimistic Locking)

概念

乐观锁假设并发冲突很少发生,因此在操作数据时不会先加锁,而是通过某种机制(如版本号)来检测是否存在冲突。只有在提交时发现冲突才会进行重试。

实现原理

  • 版本号机制: 每条记录附加一个版本号字段,每次更新时检查和更新版本号。

    1. 读取数据时,获取当前版本号。

    2. 更新数据时,检查数据库中当前版本号是否与读取时一致。

    3. 如果一致,则更新数据并将版本号加 1;如果不一致,则说明有冲突,操作失败或重试。

  • CAS (Compare and Swap): Java 的 java.util.concurrent 包中大量使用了 CAS 操作,例如 AtomicIntegerAtomicLong

    1. CAS 通过比较内存中的值和预期值,如果一致则更新,否则重试。

优缺点

  • 优点

    • 不需要实际加锁,因此开销小,性能较高。

    • 适用于读多写少的场景。

  • 缺点

    • 在高并发下,频繁重试可能影响性能。

    • 不适合写多读少的场景。

代码示例

版本号机制

// 模拟版本号机制
class Data {
    private int value;
    private int version;
​
    public synchronized boolean updateValue(int newValue, int expectedVersion) {
        if (this.version == expectedVersion) {
            this.value = newValue;
            this.version++;
            return true;
        }
        return false;
    }
}

 

CAS 操作(CAS 通过比较内存中的值和预期值,如果一致则更新,否则重试。)

import java.util.concurrent.atomic.AtomicInteger;
​
public class OptimisticLockExample {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(0);
​
        boolean success = atomicInteger.compareAndSet(0, 1);
        System.out.println("Operation success: " + success + ", New value: " + atomicInteger.get());
    }
}

  


2. 悲观锁 (Pessimistic Locking)

概念

悲观锁假设并发冲突会频繁发生,因此在操作数据时,会先加锁来阻止其他线程对数据的访问。只有当前操作完成后,其他线程才能访问。

实现原理

  • 排他锁

    1. 在操作数据前,先获取锁(独占访问)。

    2. 其他线程尝试访问时,会被阻塞直到锁被释放。

  • 数据库层面: 使用 SELECT ... FOR UPDATE 的方式锁定数据行。

  • Java 中的锁机制: 悲观锁通常使用 synchronizedjava.util.concurrent.locks.Lock 来实现。

优缺点

  • 优点

    • 能有效避免数据冲突。

    • 对于写多读少的场景更适合。

  • 缺点

    • 开销较大(需要维护锁)。

    • 在高并发场景下可能导致线程阻塞,影响性能。

代码示例

使用 synchronized

class Counter {
    private int count = 0;
​
    public synchronized void increment() {
        count++;
    }
​
    public synchronized int getCount() {
        return count;
    }
}

 

使用 Lock

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
​
class Counter {
    private int count = 0;
    private final Lock lock = new ReentrantLock();
​
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
​
    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

  


对比总结

特性乐观锁悲观锁
并发控制方式 无锁(基于版本号或 CAS) 加锁(阻塞其他线程)
性能 高(冲突少时) 低(锁管理开销大)
适用场景 读多写少 写多读少
冲突处理 依赖重试机制 阻止冲突发生
实现方式 版本号、CAS 操作 synchronized、Lock、数据库排他锁

根据具体的业务场景选择合适的锁机制。

 

标签:CAS,Java,版本号,lock,乐观,int,线程,悲观,public
From: https://www.cnblogs.com/luorongxin/p/18556362

相关文章

  • 掌握Java“时空”,工作中关于时间类的使用
    掌握Java“时空”,工作中关于时间类的使用一、Date类概述java.util.Date类表示特定的瞬间,精确到毫秒。Date类的构造函数可以把毫秒值转成日期对象构造方法publicDate()//以当前时间创建时间对象publicDate(longdate)//分配Date对象并初始化此对象,以表示自从标准基......
  • 【Java】对象和JSON字符串之间的转换 全网最清晰!
    在Java中,将对象转换为JSON字符串通常使用一些流行的JSON库,如Jackson或Gson。这两个库都非常强大,支持将Java对象转换为JSON字符串,也支持反向操作。接下来我会介绍一个基于Jackson的工具类,它可以非常方便地实现Java对象和 JSON字符串之间的相互转换。1.引......
  • 科技赋能-JAVA发票查验接口、智能、高效的代名词
    对于企业而言,确保发票的真实性和合法性,不仅关系到企业的运营风险,也直接影响到企业的信用和财务健康。翔云发票查验接口是一款通过API接口连接的发票真伪验证功能。它可以与企业的财务系统无缝对接,实现自动化的发票查验,帮助企业快速、准确地识别发票的真伪,避免因虚假发票而......
  • 复制下来就能跑 : java 免费开源 从 图片 提取文字 - 图片提取文本
    Java中图像识别后提取文字在Java开发中,图像识别中提取文字是一个常见需求,比如用于商品文字识别、文档分析等场景。传统上,这类任务多依赖OCR技术来实现,但其准确性与灵活性往往不尽人意。随着大模型技术的发展,现在可以利用这些先进的AI模型来进行图像识别,不仅提高了识别的准确......
  • springboot基于Java的城市公交调度管理系统的设计与实现
    收藏关注不迷路!!......
  • JavaFX + MySQL:动态显示数据库查询结果的JavaFX应用程序
    文章目录示例概述示例代码导入必要的包定义主类和主方法详细解释导入必要的包定义主类和主方法连接数据库并处理查询结果运行效果示例数据库表结构注意事项示例概述我们将创建一个JavaFX应用程序,该应用程序连接到MySQL数据库,查询某个表中的数据,并将结果显示在一......
  • Java API 进阶指南:从核心API到高级应用的全面提升
    文章目录JavaAPI进阶学习指南1.深入理解核心API1.1集合框架(CollectionsFramework)1.2输入输出流(I/OStreams)1.3并发编程(Concurrency)1.4反射(Reflection)1.5泛型(Generics)2.高级API应用2.1网络编程2.2数据库访问2.3日志记录2.4性能优化3.最佳实践3.1代码规......
  • Java API 学习指南:从入门到精通的全面指导
    文章目录JavaAPI学习指南1.了解JavaAPI的基本概念2.掌握基础的Java知识3.使用官方文档4.实践练习5.深入理解关键API6.关注最新的API更新7.加入社区8.创造性地应用JavaAPI学习指南1.了解JavaAPI的基本概念API是一系列预定义的函数或类,它们提供了......
  • Java面试之多线程&并发篇(6)
    前言本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!产生死锁的四个必要条件?如何避免死锁?线程池核心线程数怎么设置呢?Java线程池中队列常用类型有哪些?似乎有点模糊了,那就大概看一下面试题吧。好记性不如烂键盘***12万字的java面试题整理******java核心面试知识整理***......
  • Java OOM原因与应对
    一、引言在Java开发的世界里,内存管理是一个至关重要的环节。Java虽然有着自动内存管理机制(通过垃圾回收器,即GC来回收不再使用的对象所占用的内存),但这并不意味着开发者可以高枕无忧,内存溢出(OutOfMemory,简称OOM)问题依然可能悄然降临,给应用程序带来严重的影响,甚至导致系......