悲观锁,乐观锁,读写锁,行锁,表锁,自旋锁,死锁,分布式锁,线程同步锁,公平锁,非公平锁分别是什么

2024-07-04 08:58:53 浏览数 (2)

锁机制在并发编程和数据库管理中用于控制对资源的访问,确保数据一致性和系统稳定性。以下是各种锁的解释及其应用场景:

悲观锁(Pessimistic Lock)

  • 原理:假定会发生并发冲突,操作数据时将其锁定,直到事务结束。其他事务在此期间无法对数据进行操作。
  • 应用场景:适用于写多读少,数据冲突概率高的场景。
  • 实现方式:数据库的SELECT ... FOR UPDATE语句可以实现悲观锁。

乐观锁(Optimistic Lock)

  • 原理:假定不会发生并发冲突,操作数据时不加锁,只在提交更新时检查冲突。如果发现冲突,重试操作。
  • 应用场景:适用于读多写少,数据冲突概率低的场景。
  • 实现方式:通常通过版本号或时间戳字段实现。例如,在更新数据时检查版本号是否一致,不一致则重试。

读写锁(Read-Write Lock)

  • 原理:区分读锁和写锁。读锁允许多个线程同时读取,写锁只允许一个线程写入,且写入期间不允许读取。
  • 应用场景:读多写少的场景,提高并发度。
  • 实现方式:Java中的ReentrantReadWriteLock

行锁(Row Lock)

  • 原理:锁定数据库中的一行数据,防止其他事务对同一行数据进行并发操作。
  • 应用场景:需要对单行数据进行高并发操作的场景。
  • 实现方式:数据库的SELECT ... FOR UPDATE语句可以锁定单行记录。

表锁(Table Lock)

  • 原理:锁定整个表,防止其他事务对该表进行并发操作。
  • 应用场景:适用于需要对整个表进行批量操作的场景。
  • 实现方式:数据库的LOCK TABLES语句可以锁定表。

自旋锁(Spin Lock)

  • 原理:当一个线程尝试获取锁但失败时,不是进入休眠状态,而是循环(自旋)等待,直到成功获取锁。
  • 应用场景:锁的持有时间很短的场景,避免线程切换的开销。
  • 实现方式:Java中的Atomic包中的CAS操作(Compare-And-Swap)。

死锁(Deadlock)

  • 原理:两个或多个线程互相等待对方释放资源,导致所有线程都无法继续执行。
  • 解决方案:通过死锁检测和死锁预防算法,如银行家算法、资源申请顺序等。
  • 示例:两个线程A和B,A持有资源1等待资源2,B持有资源2等待资源1,导致互相等待无法继续。

分布式锁(Distributed Lock)

  • 原理:在分布式系统中,确保多个节点对共享资源的互斥访问。
  • 实现方式
    • 数据库实现:通过数据库行锁实现,例如MySQL的SELECT ... FOR UPDATE
    • 缓存实现:通过Redis的setnx命令。
    • Zookeeper实现:使用Zookeeper的临时节点和顺序节点。

线程同步锁(Thread Synchronization Lock)

  • 原理:确保多个线程对共享资源的互斥访问,防止线程间的竞态条件。
  • 实现方式:Java中的synchronized关键字和ReentrantLock

公平锁(Fair Lock)

  • 原理:按照线程请求锁的顺序(FIFO)获取锁,避免某些线程长期得不到锁。
  • 应用场景:需要严格控制锁的获取顺序的场景。
  • 实现方式:Java中的ReentrantLock构造函数可以设置为公平锁。

非公平锁(Non-fair Lock)

  • 原理:不保证线程获取锁的顺序,高效但可能导致某些线程长期得不到锁。
  • 应用场景:对性能要求较高,不严格要求顺序的场景。
  • 实现方式:Java中的synchronized和默认的ReentrantLock

示例代码

以下是各类锁在Java中的简单示例代码:

悲观锁(数据库示例)
代码语言:javascript复制
sql复制代码-- 悲观锁示例
BEGIN;
SELECT * FROM products WHERE product_id = 1 FOR UPDATE;
-- 进行相关操作...
COMMIT;
乐观锁(Java示例)
代码语言:javascript复制
java复制代码public boolean updateProduct(Product product) {
    String sql = "UPDATE products SET stock = ?, version = ? WHERE product_id = ? AND version = ?";
    int result = jdbcTemplate.update(sql, product.getStock(), product.getVersion()   1, product.getProductId(), product.getVersion());
    return result == 1;
}
读写锁(Java示例)
代码语言:javascript复制
java复制代码ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
Lock readLock = readWriteLock.readLock();
Lock writeLock = readWriteLock.writeLock();

public void readData() {
    readLock.lock();
    try {
        // 读取数据
    } finally {
        readLock.unlock();
    }
}

public void writeData() {
    writeLock.lock();
    try {
        // 写入数据
    } finally {
        writeLock.unlock();
    }
}
自旋锁(Java示例)
代码语言:javascript复制
java复制代码public class SpinLock {
    private AtomicReference<Thread> owner = new AtomicReference<>();

    public void lock() {
        Thread currentThread = Thread.currentThread();
        while (!owner.compareAndSet(null, currentThread)) {
            // 自旋
        }
    }

    public void unlock() {
        Thread currentThread = Thread.currentThread();
        owner.compareAndSet(currentThread, null);
    }
}
分布式锁(Redis示例)
代码语言:javascript复制
java复制代码public boolean acquireLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
    String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
    return "OK".equals(result);
}

public boolean releaseLock(Jedis jedis, String lockKey, String requestId) {
    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then "  
                    "return redis.call('del', KEYS[1]) else return 0 end";
    Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
    return "1".equals(result);
}
线程同步锁(Java示例)
代码语言:javascript复制
java复制代码public synchronized void synchronizedMethod() {
    // 同步代码块
}

public void reentrantLockMethod() {
    ReentrantLock lock = new ReentrantLock();
    lock.lock();
    try {
        // 同步代码块
    } finally {
        lock.unlock();
    }
}
公平锁与非公平锁(Java示例)
代码语言:javascript复制
java复制代码ReentrantLock fairLock = new ReentrantLock(true);  // 公平锁
ReentrantLock nonFairLock = new ReentrantLock();   // 非公平锁,默认

public void fairLockMethod() {
    fairLock.lock();
    try {
        // 同步代码块
    } finally {
        fairLock.unlock();
    }
}

总结

锁机制在并发编程和数据库管理中扮演着重要角色,选择合适的锁机制可以有效提升系统的并发性能和数据一致性。根据具体应用场景的需求,合理选择和组合锁机制,才能实现高效稳定的系统。

我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

0 人点赞