java中的乐观锁和悲观锁?

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top

全网最细面试题手册,支持艾宾浩斯记忆法。这是一份最全面、最详细、最高质量的 java面试题,不建议你死记硬背,只要每天复习一遍,有个大概印象就行了。 https://store.amazingmemo.com/chapterDetail/1685324709017001`

Java中的乐观锁和悲观锁

在并发编程中,锁是用来控制多个线程访问共享资源的一种机制。在Java中,乐观锁和悲观锁是两种常见的锁机制,它们用于处理不同的并发冲突。

悲观锁(Pessimistic Locking)

悲观锁假设最坏的情况,即在任何时候都认为其他线程会尝试修改共享数据。因此,它会在数据被处理之前先加锁,确保其他线程无法访问该数据。这种锁的特点是在整个数据处理过程中持有锁,直到事务完成。

特点:

  • 阻塞性:当一个线程持有锁时,其他所有需要该锁的线程都会被阻塞。

  • 数据安全:由于在整个数据处理过程中都持有锁,因此可以保证数据的安全性。

  • 可能导致死锁:如果不同的线程以不同的顺序请求锁,可能会导致死锁。

示例:

在Java中,悲观锁可以通过synchronized关键字或者ReentrantLock类实现。

public class PessimisticLockExample {
    private final ReentrantLock lock = new ReentrantLock();

    public void performTask() {
        lock.lock();
        try {
            // 访问或修改共享资源
        } finally {
            lock.unlock();
        }
    }
}

乐观锁(Optimistic Locking)

乐观锁则是一种更加宽松的锁机制,它假设多数情况下不会发生修改冲突。乐观锁通常不会直接阻止其他线程对数据的访问,而是在数据提交更新时检查是否有冲突发生。

特点:

  • 非阻塞性:线程不会因为尝试访问数据而被阻塞。

  • 版本控制:通常通过数据版本号(如数据库中的时间戳或版本字段)来实现。

  • 冲突解决:如果检测到冲突,可以重试操作或者回滚。

示例:

在数据库中,乐观锁通常通过在表中添加一个版本号字段来实现。在更新记录时,会检查版本号是否发生变化。

UPDATE table_name SET column1 = value1, version = version + 1 WHERE id = some_id AND version = current_version;

在Java代码中,可以使用AtomicIntegerAtomicReference等原子类来实现乐观锁。

public class OptimisticLockExample {
    private final AtomicInteger version = new AtomicInteger(0);

    public void performTask() {
        int currentVersion = version.get();
        // 访问或修改共享资源
        // 在提交更新前检查版本号是否发生变化
        if (!version.compareAndSet(currentVersion, currentVersion + 1)) {
            // 如果版本号发生变化,说明有其他线程已经修改了数据,可以重试或者回滚操作
        }
    }
}

总结

悲观锁和乐观锁是处理并发问题的两种不同策略。悲观锁适用于写操作多的场景,可以避免数据不一致的问题,但可能会降低系统的吞吐量。乐观锁适用于读操作多的场景,系统吞吐量较高,但需要处理冲突的可能性。在实际应用中,选择合适的锁策略对于提高系统性能和可靠性至关重要。

最后更新于