使用redis来完成分布式锁
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.properties
#redis jedis配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
#spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=-1
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=8
# 连接超时时间(毫秒)
spring.redis.timeout=4000
对jedispool进行配置
package com.example.demo.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @program: demoA
* @description
* @author: dajitui
* @create: 2019-01-03 23:17
**/
@EnableCaching
@Configuration
public class JedisConfig extends CachingConfigurerSupport {
private Logger logger = LoggerFactory.getLogger(JedisConfig.class);
/**
* SpringSession 需要注意的就是redis需要2.8以上版本,然后开启事件通知,在redis配置文件里面加上
* notify-keyspace-events Ex
* Keyspace notifications功能默认是关闭的(默认地,Keyspace 时间通知功能是禁用的,因为它或多或少会使用一些CPU的资源)。
* 或是使用如下命令:
* redis-cli config set notify-keyspace-events Egx
* 如果你的Redis不是你自己维护的,比如你是使用阿里云的Redis数据库,你不能够更改它的配置,那么可以使用如下方法:在applicationContext.xml中配置
* <util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
* @return
*/
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.pool.min-idle}")
private int minIdle;
@Value("${spring.redis.pool.max-wait}")
private long maxWaitMillis;
@Bean
public JedisPool redisPoolFactory(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMaxTotal(maxActive);
jedisPoolConfig.setMinIdle(minIdle);
JedisPool jedisPool = new JedisPool(jedisPoolConfig,host,port,timeout);
logger.info("JedisPool注入成功!");
logger.info("redis地址:" + host + ":" + port);
return jedisPool;
}
}
编写分布式锁
package com.example.demo.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Collections;
/**
* @program: demoA
* @description
* @author: dajitui
* @create: 2019-01-03 23:03
**/
@Component
public class Rlock {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private static final long expireTime = 5000;
private static final Long RELEASE_SUCCESS = 1L;
private static String lockKey="message";
@Autowired
JedisPool jedisPool;
/**
* 请求id
* @param requestid
* @return
*/
public boolean lock(String requestid){
Jedis jedis=jedisPool.getResource();
String result=jedis.set(lockKey, requestid, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
/**
* 请求id
* @param requestid
* @return
*/
public boolean unlock(String requestid){
Jedis jedis=jedisPool.getResource();
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestid));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
具体的自行百度哦~
测试类
package com.example.demo;
/**
* @program: demoA
* @description
* @author: dajitui
* @create: 2019-01-04 02:16
**/
public class A {
public static int a=1000;
public static void f(){
a--;
}
}
package com.example.demo;
import com.example.demo.RedisUtil.Rlock;
import com.example.demo.entity.message;
import com.example.demo.mq.JMSProducer;
import org.apache.activemq.command.ActiveMQQueue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.JedisPool;
import javax.jms.Destination;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Test
public void testa(){
CountDownLatch countDownLatch=new CountDownLatch(100);
for(int i=0;i<100;i++){
//countDownLatch.countDown();
/*MyThread myThread=new MyThread();
myThread.start();*/
new Thread(new Runnable() {
@Override
public void run() {
while (true){
if (rlock.lock("1")){
System.out.println("获取到锁,开始执行减一操作");
A.f();
System.out.println(A.a);
if(rlock.unlock("1")){
System.out.println("释放锁成功");
break;
}else {
System.out.println("释放锁失败!!!");
}
}else {
System.out.println("获取不到锁,等待......");
int random= (int) (Math.random()*10000);
try {
Thread.sleep(random);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*if (rlock.lock("1")){
System.out.println("获取到锁,开始执行减一操作");
A.f();
System.out.println(A.a);
if(rlock.unlock("1")){
System.out.println("释放锁成功");
//break;
}else {
System.out.println("释放锁失败!!!");
}
}else{
System.out.println("获取不到锁,等待2秒......");
int random= (int) (Math.random()*10000);
try {
Thread.sleep(1000+ random);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (rlock.lock("1")){
A.f();
System.out.println(A.a);
if(rlock.unlock("1")){
System.out.println("释放锁成功");
//break;
}else {
System.out.println("释放锁失败!!!");
}
}else {
//System.out.println("获取不到锁.......");
try {
Thread.sleep(random);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (rlock.lock("1")){
A.f();
System.out.println(A.a);
if(rlock.unlock("1")){
System.out.println("释放锁成功");
//break;
}else {
System.out.println("释放锁失败!!!");
}
}else {
System.out.println("获取不到锁.......");
}
}
}*/
}
}).start();
}
/*try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
@Autowired
Rlock rlock;
}
如何续期
我们可以看到在调用lock()的时候会调用tryAcquire尝试获取锁,在获取到锁的时候会开启一个开门狗的线程,默认锁30秒过期,当