【26、悲观锁与乐观锁的原理及实现】

128 阅读2分钟

Java中的锁机制是多线程编程中常用的同步机制,主要用于控制共享资源的访问。Java中的锁分为悲观锁和乐观锁两种,本文将介绍它们的原理及实现方式。

悲观锁

悲观锁的基本思想是,当线程访问共享资源时,认为其他线程可能会修改数据,因此需要加锁保护共享资源。悲观锁实现起来比较简单,通常使用synchronized关键字来实现。

举个例子,假设有一个共享变量count,多个线程同时对它进行累加操作,代码如下:

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
    
    public int getCount() {
        return count;
    }

}

上面的代码使用synchronized关键字对increment方法进行加锁,保证多个线程对count变量的访问是同步的。

乐观锁

乐观锁的基本思想是,当线程访问共享资源时,认为其他线程不会修改数据,因此不需要加锁,而是在更新数据时判断是否被其他线程修改过,如果没有被修改,则更新成功,否则需要重试。

乐观锁的实现方式有很多种,其中最常用的是基于版本号(Version Number)的乐观锁。每个共享数据都维护一个版本号,当线程更新数据时,先读取当前的版本号,然后尝试更新数据,如果版本号未发生变化,则更新成功,否则需要重试。

举个例子,假设有一个共享变量count,多个线程同时对它进行累加操作,代码如下:

public class Counter {
    private int count = 0;
    private int version = 0;

    public void increment() {
        int currentVersion = version;
        while (true) {
            if (compareAndSet(currentVersion)) {
                count++;
                break;
            }
        }
    }
    
    public int getCount() {
        return count;
    }
    
    public synchronized boolean compareAndSet(int expectVersion) {
        if (version == expectVersion) {
            version++;
            return true;
        }
        return false;
    }

}

上面的代码使用compareAndSet方法实现了基于版本号的乐观锁。increment方法先读取当前的版本号,然后在一个while循环中不断尝试更新数据,如果compareAndSet方法返回true,则表示更新成功,否则需要继续重试。

总之,悲观锁和乐观锁是Java中常用的两种锁机制,悲观锁通过加锁保护共享资源,保证线程安全,而乐观锁则通过无锁编程的方式提高并发性能。开发人员需要根据实践场景选择适应的锁。