redis lock
单机lock
- synchronized
- reentrantLock
- cas
分布式lock
- redis lock
- zookeeper lock
- 数据库行锁
redis能称为分布式锁的条件
- 互斥性
- 原子性
redis加锁流程
踩过的坑
线程A获得redis的锁,执行业务发生超时释放锁,线程B获得线程A释放的锁,线程A业务执行结束,释放了线程B的锁 解决办法:每个线程获取锁,设置不同value值,线程释放锁的时候,将原先线程设置的value与当前锁的value做比较,相同时释放锁
优化的点
1、删除锁并非原子性操作
public void unlock() {
String value = convertValue();
//1.获取lockValue
String lockValue = RedisProxyUtil.getCacheInstance().getJedisReturn().get(name);
//2.释放锁
if (value.equalsIgnoreCase(lockValue)) {
RedisProxyUtil.getCacheInstance().getJedisReturn().del(name);
}
}
复制代码
可能出现的情况 线程A同时出现超时和业务执行结束,那么线程A会出现两次释放锁,两次释放锁第一步都走完了,其中一个释放锁的线程1、2都走完了,导致线程B获得锁,线程A另一个线程进行步骤二释放了线程B的锁
解决方法:可以使用lua脚本进行原子删除操作
public void unlock() {
String checkAndDelScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else " +
"return 0 " +
"end";
jedis.eval(checkAndDelScript, 1, lockKey, lockValue);
}
复制代码
2、自己实现redis锁不易维护,可以使用Redisson,话不多说,上代码
/**
* @author jujunjun
* @version v1.0.0
* @date 2018/8/30
*/
public class RedissonTest {
public static RedissonClient redisson;
static {
Config config = new Config();
config.useSingleServer().setAddress("redis://10.30.130.180:6379");
redisson = Redisson.create(config);
}
public static void main(String[] args){
ExecutorService executorService = Executors.newFixedThreadPool(5);
for(int i = 0; i < 5; i++) {
executorService.execute(()-> testLock());
}
}
private static void testLock() {
RLock rLock = redisson.getLock("junjunlock");
try {
/* 尝试加锁 */
boolean lock = rLock.tryLock(10, 10, TimeUnit.SECONDS);
if(lock) {
System.out.println(Thread.currentThread().getName()+ "------" + System.currentTimeMillis());
Thread.sleep(2000);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
/* 释放锁 */
rLock.unlock();
}
}
}
复制代码
zookeeper lock
流程
package com.code.web.service;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author jujunjun
* @version v1.0.0
* @date 2018/8/31
*/
public class ZookeeperLock {
public static CuratorFramework client;
static {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
client = CuratorFrameworkFactory.newClient("10.30.130.180:2181", retryPolicy);
}
public static void main(String[] args) throws Exception {
client.start();
InterProcessMutex mutex = new InterProcessMutex(client, "/curator/lock");
ExecutorService executorService = Executors.newFixedThreadPool(5);
for(int i = 0; i < 5; i++) {
executorService.execute(()-> testLock(mutex));
}
}
private static void testLock(InterProcessMutex mutex) {
try {
mutex.acquire();
System.out.println(Thread.currentThread().getName()+ "------" + System.currentTimeMillis());
Thread.sleep(2000);
mutex.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码