一. redis 实现分布式锁
- 利用 redis 单线程,不能存储相同key,可以设置存储数据失效的特性实现分布式锁,重点方法时setnx(),存储,存储成功返回1,失败返回0,
- 当获取锁时存储调用setnx()方法存储一个代表锁的key,该key对应一个可以代表唯一的变量,并将该变量返回
- 获取锁成功后调用 expire(lockName, time) 对当前代表锁的key设置失效时间,防止死锁
- 如果存储失败说明前面有线程获取到了锁,当前线程阻塞等待(或while循环一不停调用获取锁的方法,直至获取成功)
- 当需要加锁执行的代码执行完毕后,删除redis中这个代表锁的key,删除前获取该key存储的数据与上面返回的数据是否是同一个,是否是一把锁,删除释放
- 代码示例
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.UUID;
public class LockRedis {
private JedisPool jedisPool;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(200);
config.setMaxIdle(8);
config.setMaxWaitMillis(1000 * 100);
config.setTestOnBorrow(true);
jedisPool= new JedisPool(config, "39.107.69.43", 6379, 3000);
}
public String lockWithTimeout(String lockKey, Long acquireTimeout, Long timeOut) {
Jedis conn = null;
String retIdentifierValue = null;
try {
conn = jedisPool.getResource();
String identifierValue = UUID.randomUUID().toString();
String lockName = "redis_lock" + lockKey;
int expireLock = (int) (timeOut / 1000);
Long endTime = System.currentTimeMillis() + acquireTimeout;
while (System.currentTimeMillis() < endTime) {
if (conn.setnx(lockName, identifierValue) == 1) {
conn.expire(lockName, expireLock);
retIdentifierValue = identifierValue;
return retIdentifierValue;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.close();
}
}
return retIdentifierValue;
}
public boolean releaseLock(String lockKey, String identifier) {
Jedis conn = null;
boolean flag = false;
try {
conn = jedisPool.getResource();
String lockName = "redis_lock" + lockKey;
if (identifier.equals(conn.get(lockName))) {
conn.del(lockName);
System.out.println(identifier + "解锁成功......");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.close();
}
}
return flag;
}
}
- 调用测试
public static void main(String[] args) {
LockRedis lockRedis = new LockRedis();
String identifier = lockRedis.lockWithTimeout("lock", 5000L, 5000L);
if (StringUtils.isEmpty(identifier)) {
System.out.println(Thread.currentThread().getName() + ",获取锁失败,原因时间超时!!!");
}
}
二. redis 生成分布式全局ID
- 利用了 redis 单线程,保证原子性,不依赖数据库,生成id可以自增,天然排序等特性
- 注意点redis集群时多个写库,注意设置步长,与生成的id起始值
- 利用 RedisAtomicLong 调用 RedisAtomicLong () 方法
@Autowired
private StringRedisTemplate stringRedisTemplate;
public String order(String key) {
RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, stringRedisTemplate.getConnectionFactory());
long andIncrement = redisAtomicLong.getAndIncrement();
String orderId = prefix() + "-" + String.format("%1$05d", andIncrement);
return orderId;
}
public static String prefix() {
String temp_str = "";
Date dt = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
temp_str = sdf.format(dt);
return temp_str;
}
- 步长与起始值设置
redisAtomicLong.set(0);
redisAtomicLong.addAndGet(9);