分布式锁
场景演示为什么需要分布式锁
场景:一个订单表,库存表,支付表,多个用户对库存操作。当前库存为1
public class Order {
public void createOrder(){
System.out.println(Thread.currentThread().getName()+" 创建订单");
}
}
public class Pay {
public static void pay(){
System.out.println(Thread.currentThread().getName()+" 支付成功!");
}
}
public class Stock {
private static Integer COUNT = 1;
public boolean reduceStock(){
if(COUNT > 0){
COUNT – ;
return true;
}
return false;
}
}
如图所示:
模拟了两个用户对库存只有一时,两个用户都成功减库存成功了,并且支付成功了,所有在分布式系统中,需要有分布式锁控制同一时间只有一个用户进来访问。
分布式系统:表示有多个进程提供服务,完成一件事。
public class Main {
//模拟两个用户同时抢订单
public static void main(String[] args) {
Thread user1 = new Thread(new UserThread(),“user1”);
Thread user2 = new Thread(new UserThread(),“user2”);
user1.start();
user2.start();
}
static class UserThread implements Runnable{
@Override
public void run() {
new Order().createOrder();
Boolean result = new Stock().reduceStock();
if(result){
System.out.println(Thread.currentThread().getName() + " 减库存成功");
new Pay().pay();
}else{
System.out.println(Thread.currentThread().getName()+" 减库存失败");
}
}
}
}
redis分布式锁实现
package com.wf.springdemo.locktest;/**
- Created by wufei on 2018/12/10.
*/
import com.wf.springdemo.locktest.redislock.RedisLock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
- @author wufei
- @create 2018-12-10 9:12
**/
public class Main {
//模拟两个用户同时抢订单
public static void main(String[] args) {
Thread user1 = new Thread(new UserThread(),“user1”);
Thread user2 = new Thread(new UserThread(),“user2”);
user1.start();
user2.start();
}
//public static Lock lock = new ReentrantLock();
public static Lock lock = new RedisLock();
static class UserThread implements Runnable{
@Override
public void run() {
new Order().createOrder();
lock.lock();
Boolean result = new Stock().reduceStock();
lock.unlock();
if(result){
System.out.println(Thread.currentThread().getName() + " 减库存成功");
new Pay().pay();
}else{
System.out.println(Thread.currentThread().getName()+" 减库存失败");
}
}
}
}
package com.wf.springdemo.locktest.redislock;/**
- Created by wufei on 2018/12/10.
*/
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
-
@author wufei
-
@create 2018-12-10 9:30
**/
public class RedisLock implements Lock {
private static String LOCK_NAME = “redis_lock”;
private static String REQUEST_ID = “123456”;ThreadLocal jedis = new ThreadLocal();
//加锁
@Override
public void lock() {
init();
if(tryLock()){//如果没有锁则加锁
//如果某个应用节点挂了,不能释放锁了也就是不能进入unlock()方法了,这个情况怎么办呢?设置过期时间
// jedis.set(LOCK_NAME,REQUEST_ID);
// jedis.expire(LOCK_NAME,3000);//设置过期时间
//但是这个时间不是原子性,执行到jedis.set方法了,但是应用挂了,没有执行jedis.expire,所有还会导致无法释放锁。
//怎么设置原子性呢。
jedis.get().set(LOCK_NAME,REQUEST_ID,“NX”,“PX”,3000);
}
}/**
- 获取锁 true 没有锁,false 有锁
- @return
*/
@Override
public boolean tryLock() {
//不停的获取锁
while (true){
//获取锁,怎样保证原子性呢 使用setnx方法
//key不存在返回1,存在返回0
//String lock = jedis.get(LOCK_NAME);
Long lock = jedis.get().setnx(LOCK_NAME,REQUEST_ID);
if(lock ==1){
return true;
}
}
}
/**
-
释放锁
*/
@Override
public void unlock() {
//释放自己设置的锁,
// String value = jedis.get().get(LOCK_NAME);
// if(REQUEST_ID.equals(value)){
// jedis.get().del(LOCK_NAME);
// }
//原子性 使用lua
// String script = “if redis.call(‘get’,KEYS[1]==ARGV[1]) then return redis.call(‘del’,KEYS[1]) else return 0 end”;
// jedis.get().eval(script, Collections.singletonList(LOCK_NAME),Collections.singletonList(REQUEST_ID));//lua script
String script = “if redis.call(‘get’, KEYS[1]) == ARGV[1] then return redis.call(‘del’, KEYS[1]) else return 0 end”;
Object result = jedis.get().eval(script, Collections.singletonList(LOCK_NAME), Collections.singletonList(REQUEST_ID));
}
private void init(){
if(jedis.get() == null){
jedis.set(new Jedis(“localhost”));
}
}@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void lockInterruptibly() throws InterruptedException {}
@Override
public Condition newCondition() {
return null;
}
}
zk分布式锁实现