Java中的悲观锁和乐观锁怎么实现

发布时间:2023-04-20 11:36:49 作者:iii
来源:亿速云 阅读:106

今天小编给大家分享一下Java中的悲观锁和乐观锁怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

悲观锁(Pessimistic Locking)

悲观锁在并发环境中认为数据随时会被其他线程修改,因此每次在访问数据时都会加锁,直到操作完成后才释放锁。悲观锁适用于写操作多、竞争激烈的场景,比如多个线程同时对同一数据进行修改或删除操作的情况。悲观锁可以保证数据的一致性,避免脏读、幻读等问题的发生

悲观锁就像一个大保安,总是认为有坏人想要偷走共享资源,于是它把资源护得紧紧的,不让任何人接近,同时还会排队等待资源,想要使用就得先获取锁,这样虽然安全可靠,但是也会导致效率低下,因为别的线程必须等待锁的释放才能继续执行。

Java中常用的悲观锁是synchronized关键字和ReentrantLock类。

使用synchronized关键字实现悲观锁的代码如下:

synchronized (lock) {
    //访问共享资源的代码块
}

使用ReentrantLock实现悲观锁的代码如下:

ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    //访问共享资源的代码块
} finally {
    lock.unlock();
}

悲观锁存的问题:

乐观锁

乐观锁在并发环境中认为数据一般情况下不会被其他线程修改,因此在访问数据时不加锁,而是在更新数据时进行检查。如果检查到数据被其他线程修改,则放弃当前操作,重新尝试更新。

乐观锁适用于读操作多、写操作少的场景,比如多个线程同时对同一数据进行读取操作的情况。乐观锁可以减少锁的竞争,提高系统的并发性能。

乐观锁就像一个乐天派,总是认为没有坏人想要偷走共享资源,于是它就不怎么防范,直接对资源进行操作,如果没有其他线程对资源进行修改,操作就会成功,否则就会进行重试,这样虽然效率高,但是如果多个线程同时进行修改,就会导致竞争和冲突,需要进行额外的处理。

Java中常用的乐观锁是基于CAS(Compare and Swap,比较和交换)算法实现的。

CAS操作包括三个操作数:内存地址V旧的预期值A新的值B。CAS操作首先读取内存地址V中的值,如果该值等于旧的预期值A,那么将内存地址V中的值更新为新的值B;

否则,不进行任何操作。在更新过程中,如果有其他线程同时对该共享资源进行了修改,那么CAS操作会失败,此时需要重试更新操作。

下面是一段基于CAS算法实现的乐观锁代码:

// 假设共享资源为变量value,初始值为1
AtomicInteger value = new AtomicInteger(1);
// 假设旧的预期值为1,新的值为2
int expect = 1;
int update = 2;

// 使用CAS操作更新共享资源的值
while (true) {
    // 读取共享资源的当前值
    int current = value.get();
    // 如果当前值等于旧的预期值,使用CAS操作将新的值更新到共享资源中
    if (current == expect) {
        if (value.compareAndSet(expect, update)) {
            // 更新成功,退出循环
            break;
        } else {
            // 更新失败,可能是因为其他线程修改了共享资源的值,重试更新操作
            continue;
        }
    } else {
        // 当前值不等于旧的预期值,说明共享资源的值已经被其他线程修改,重试更新操作
        continue;
    }
}

在这段代码中,内存地址V对应的是AtomicInteger对象value旧的预期值A对应的是变量expect新的值B对应的是变量update。使用AtomicInteger对象可以保证CAS操作的原子性,即只有一个线程能够成功更新共享资源的值。使用compareAndSet方法可以判断共享资源的值是否等于旧的预期值,并尝试将新的值更新到共享资源中。如果更新成功,就退出循环;否则,说明共享资源的值已经被其他线程修改,需要重试更新操作。

在实际应用中,乐观锁的实现通常比这个简单实现要复杂。例如,在对数据库中的数据进行更新时,需要在更新操作中同时更新版本号和其他字段的值,并且需要处理更新失败和重试的情况。

乐观锁存在的问题

CAS虽然很⾼效的解决原⼦操作,但是CAS仍然存在三⼤问题:ABA问题自旋时间过长只能保证单个变量的原子性

悲观锁和乐观锁的对比


悲观锁乐观锁
性能
数据一致性
实现复杂度简单复杂
加锁方式基于锁机制基于版本号机制
应用场景读少写多读多写少
存在的问题效率低、容易引起死锁、可能会引起线程阻塞ABA问题、自旋时间过长、只能保证单个变量的原子性

以上就是“Java中的悲观锁和乐观锁怎么实现”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。

推荐阅读:
  1. 从零开始学大数据-Java基础-switch语句(6)
  2. linux中使用yum配置java环境

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:Python matplotlib怎么调整坐标轴位置、标签位置、标签方向及X轴刻度标签位置

下一篇:Spring中怎么利用IOC实现注入

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》