Skip to content

分布式锁

什么是分布式锁

锁分为线程级别锁,和应用级别的锁

线程级别说的是在单体应用中,对单个项目进行锁

分布式锁是在分布式环境下保证数据单一操作的锁

为什么需要分布式锁

任何一个分布式系统都无法同时满足

  • 一致性(Consistency)

  • 可用性(Availability)

  • 分区容错性(Partition tolerance)

如果我们需要满足分布式系统的一致性的话,必须使用分布式锁

来保证数据的一致性,保证一个方法在同一时间内只能被同一个线程执行。

目前有3种解决方法

  • 基于数据库实现分布式锁;
  • 基于缓存(Redis等)实现分布式锁;
  • 基于Zookeeper实现分布式锁;

怎么使用分布式锁

0.lock对象

jkd1.5

java
java.util.concurrent.locks.Lock;

与使用synchronized方法和语句相比, Lock实现提供了更广泛的锁操作。 它们允许更灵活的结构,可以具有完全不同的属性,

java
public interface Lock {
    // 加锁
    void lock();
    //除非当前线程被中断,否则获取锁
    void lockInterruptibly() throws InterruptedException;
    // 尝试获取锁
    boolean tryLock();
    // 尝试获取锁 time 等待的最长时间
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    // 释放锁
    void unlock();
    // 返回一个 Condition 对象 
    //Condition对象拥有await()和signal(),和wait()、notify()效果类似
    Condition newCondition();
}

我们创建一个Ticket

java
public class Ticket {
    // 剩余的票数量
    public static int num = 1;

    // 库存-1
    public  boolean desc(){
        if (num>0){
            num--;
            return true;
        }
        return false;
    }

}

写一个测试类测试

java
public class LockTest {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            executorService.execute(()->{
                boolean desc = Ticket.desc();
                if (desc){
                    System.out.println(Thread.currentThread().getName()+":减少成功");
                }else {
                    System.out.println(Thread.currentThread().getName()+":减少失败");
                }
            });
        }

        executorService.shutdown();
    }

}

这种情况不会出现线程不安全问题,

我们在买票的时候可能会出现一些网络波动,我们给上面desc方法添加一点休眠

java
// 库存-1
public  boolean desc(){
    if (num>0){
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        num--;
        return true;
    }
    return false;
}

这样肯定会出现多个成功,不是我们所预期的,我们尝试给他加锁

java
public class LockTest {
    public static void main(String[] args) {
        Lock baseLock = new ReentrantLock();
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            executorService.execute(()->{
                baseLock.lock();
                boolean desc = Ticket.desc();
                baseLock.unlock();
                if (desc){
                    System.out.println(Thread.currentThread().getName()+":减少成功");
                }else {
                    System.out.println(Thread.currentThread().getName()+":减少失败");
                }
            });
        }

        executorService.shutdown();
    }
}

这样就保证了单一项目架构的锁,但是,分布式环境下,这样就锁不住了,因为不同的服务是部署在不同服务器上,不处于同一个jvm环境中,因此,我们需要借助第三方的环境

1.mysql分布式锁

创建一张表,用于记录锁

sql
create table `t_lock`
(
    id       int auto_increment
        primary key,
    lockName int null,
    constraint lock_lockName_uindex
        unique (lockName)
);

2.redis分布式锁

3.zopkeeper 分布式锁