分布式锁
什么是分布式锁
锁分为线程级别锁,和应用级别的锁
线程级别说的是在单体应用中,对单个项目进行锁
分布式锁是在分布式环境下保证数据单一操作的锁
为什么需要分布式锁
任何一个分布式系统都无法同时满足
一致性(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)
);