package com.rdj.distributelock; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling public class DistributeLockApplication { public static void main(String[] args) { SpringApplication.run(DistributeLockApplication.class, args); } } //service package com.rdj.distributelock.service; import com.rdj.distributelock.lock.RedisLock; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; /** * redis 分布式锁实现定时任务 */ @Service @Slf4j public class SchedulerService { @Autowired private RedisTemplate redisTemplate; //模拟每隔5秒执行一次 @Scheduled(cron = "*/5 * * * * ?") public void sendSms(){ try(RedisLock redisLock = new RedisLock(redisTemplate,"autoSms",30)) { if (redisLock.getLock()) { //获取到锁,才执行定时任务 log.info("发送短信"); } } catch (Exception e) { e.printStackTrace(); } } } package com.rdj.distributelock.lock; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.data.redis.core.types.Expiration; import java.util.Arrays; import java.util.List; import java.util.UUID; //AutoCloseable jdk1.7 后增加的 自动关闭特性 @Slf4j public class RedisLock implements AutoCloseable{ private RedisTemplate redisTemplate; private String key; private String value; private int expireTime;//过期时间,单位秒 public RedisLock(RedisTemplate redisTemplate, String key,int expireTime){ this.redisTemplate = redisTemplate; this.key = key; this.expireTime = expireTime; this.value = UUID.randomUUID().toString(); } /** * 获取分布式锁 * @return */ public boolean getLock(){ RedisCallback<Boolean> redisCallback = connection -> { RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent(); Expiration expiration = Expiration.seconds(expireTime); byte[] redisKey = redisTemplate.getKeySerializer().serialize(key); byte[] redisValue = redisTemplate.getKeySerializer().serialize(value); Boolean result = connection.set(redisKey, redisValue, expiration, setOption); return result; }; boolean lock = (boolean) redisTemplate.execute(redisCallback); return lock; } public boolean unLock(){ String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" + " return redis.call(\"del\",KEYS[1])\n" + "else\n" + " return 0\n" + "end"; RedisScript<Boolean> redisScript = RedisScript.of(script,Boolean.class); List<String> keys = Arrays.asList(key); Boolean res = (Boolean) redisTemplate.execute(redisScript, keys, value); log.info("释放锁的结果 {}",res); return res; } @Override public void close() throws Exception { unLock(); } }