在 Redis 里,所谓 SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果!
以下的方法主要用于一个应用部署到多个服务器下定时任务只有一个服务器执行
/** * 判断定时任务是否可以执行 * 如果key已经存在,那么返回0,不覆盖 * 如果key不存在,则设置一个新value,返回1 * @return */ public synchronized boolean canUseTaskFlag(String redisKey,Long timeout) { String expiresStrTime = String.valueOf(System.currentTimeMillis() + timeout); //锁到期时间 if (redisClient.setnx(redisKey, expiresStrTime) == 1) { log.info(" redisKey = "+ redisKey +" and expiresStrTime = "+expiresStrTime+" and run flag is true"); return true; } String currentValueStr = redisClient.get(redisKey); //redis里的时间 if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { //判断是否为空,不为空的情况下,如果被其他线程设置了值,则第二个条件判断是过不去的 // lock is expired String oldValueStr = redisClient.getsetValue(redisKey, expiresStrTime); //获取上一个锁到期时间,并设置现在的锁到期时间, //只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的 if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { //如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁 // lock acquired log.info(" redisKey = "+ redisKey +" and expiresStrTime = "+expiresStrTime+" and run flag is true"); return true; } } log.info(" redisKey = "+ redisKey +" and expiresStrTime = "+expiresStrTime+" and run flag is false"); return false; }
使用DEMO
public void testUse() { try { //为了防止redis同一时间被调用 Thread.sleep(700); //如果key已经存在,那么返回0,不覆盖 //如果key不存在,则设置一个新value,返回1 boolean flag = canUseTaskFlag("test_key",10L*60*1000L - 1L);//每10分钟执行一次 if (flag){ //可以执行 } redisClient.delKey("test_key"); } catch (Exception e) { redisClient.delKey("test_key"); e.printStackTrace(); } }