高并发环境下,Redisson实现redis分布式锁

 

原文:http://tlzl0526-gmail-com.iteye.com/blog/2378853

 

在一些高并发的场景中,比如秒杀,抢票,抢购这些场景,都存在对核心资源,商品库存的争夺,控制不好,库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis官方推荐使用的Redisson就提供了分布式锁和相关服务。 
下面介绍下如何使用Redisson。 

Xml代码  收藏代码

  1. <dependency>  
  2.         <groupId>org.redisson</groupId>  
  3.         <artifactId>redisson</artifactId>  
  4.          <version>2.7.0</version>   
  5.  </dependency>  


使用redisson,最好采用redis 2.6.0以上版本,因为redosson一些后台命令采用eval的命令 
 

Java代码  收藏代码

  1. import org.redisson.Redisson;  
  2. import org.redisson.api.RAtomicLong;  
  3. import org.redisson.config.Config;  
  4.   
  5. public class RedissonManager {  
  6.   
  7.     private static final String RAtomicName = "genId_";  
  8.   
  9.     private static Config config = new Config();  
  10.     private static Redisson redisson = null;  
  11.   
  12.    public static void init(String key,String value){  
  13.         try {  
  14. /*            config.useClusterServers() //这是用的集群server 
  15.                     .setScanInterval(2000) //设置集群状态扫描时间 
  16.                     .setMasterConnectionPoolSize(10000) //设置连接数 
  17.                     .setSlaveConnectionPoolSize(10000) 
  18.                     .addNodeAddress("127.0.0.1:6379");*/  
  19.             if(key==null || "".equals(key)){  
  20.                 key=RAtomicName;  
  21.             }  
  22.             config.useSingleServer().setAddress("127.0.0.1:6379");  
  23.             redisson = (Redisson) Redisson.create(config);  
  24.             //清空自增的ID数字  
  25.             RAtomicLong atomicLong = redisson.getAtomicLong(key);  
  26.             long pValue=1;  
  27.             if(value!=null && !"".equals(value)){  
  28.                 pValue = Long.parseLong(value);  
  29.             }  
  30.             atomicLong.set(pValue);  
  31.         }catch (Exception e){  
  32.             e.printStackTrace();  
  33.         }  
  34.     }  
  35.   
  36.     public static Redisson getRedisson(){  
  37.         return redisson;  
  38.     }  
  39.   
  40.     /** 获取redis中的原子ID */  
  41.     public static Long nextID(){  
  42.         RAtomicLong atomicLong = getRedisson().getAtomicLong(RAtomicName);  
  43.        //原子性的获取下一个ID,递增1   
  44.        atomicLong.incrementAndGet();  
  45.         return atomicLong.get();  
  46.     }  
  47. }  



加锁和释放锁的方法,设置超时 
 

Java代码  收藏代码

  1. public class DistributedRedisLock {  
  2.     private static Redisson redisson = RedissonManager.getRedisson();  
  3.     private static final String LOCK_TITLE = "redisLock_";  
  4.   
  5.     public static boolean acquire(String lockName){  
  6.         String key = LOCK_TITLE + lockName;  
  7.         RLock mylock = redisson.getLock(key);  
  8.         mylock.lock(2, TimeUnit.MINUTES); //lock提供带timeout参数,timeout结束强制解锁,防止死锁  
  9.         System.err.println("======lock======"+Thread.currentThread().getName());  
  10.         return  true;  
  11.     }  
  12.   
  13.     public static void release(String lockName){  
  14.         String key = LOCK_TITLE + lockName;  
  15.         RLock mylock = redisson.getLock(key);  
  16.         mylock.unlock();  
  17.         System.err.println("======unlock======"+Thread.currentThread().getName());  
  18.     }  
  19. }  



在web端,controller中 

Java代码  收藏代码

  1. @RequestMapping("/redder")  
  2. @ResponseBody  
  3. public String redder() throws IOException{  
  4.      String key = "test123";  
  5.        
  6.   DistributedRedisLock.acquire(key);  
  7.           
  8.            
  9.   Long result =  RedissonManager.nextID();    
  10.   
  11.     DistributedRedisLock.release(key);  
  12.     return ""+result;   
  13. }  



程序首先要设置 RedissonManager.init("","");  进行初始化,这样的目的主要是可以根据实际情况,设置对应的信息,设置递增的初始值。 

目前用jmeter的测试,1000的并发,确保ID设置为1001

### 回答1: 好的,这是一个使用 Redission 和 RedisTemplate 设计的 Java 代码,用来监控高并发情况下用户完成阅读任务上限后再次完成的场景的例子: ``` import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; public class UserReadingTask { @Autowired private RedisTemplate<String, Integer> redisTemplate; @Autowired private RedissonClient redissonClient; // 用户完成阅读任务的上限 private static final int READING_TASK_LIMIT = 100; public void completeReadingTask(String userId) { // 使用 RedisTemplate 获取用户已完成的阅读任务数 ValueOperations<String, Integer> ops = redisTemplate.opsForValue(); Integer completedTasks = ops.get(userId); if (completedTasks == null) { completedTasks = 0; } // 如果用户已完成的阅读任务数达到上限,则不再完成任务 if (completedTasks >= READING_TASK_LIMIT) { return; } // 使用 Redission 获取分布式锁 RLock lock = redissonClient.getLock(userId); lock.lock(); try { // 再次获取用户已完成的阅读任务数 completedTasks = ops.get(userId); // 如果用户已完成的阅读任务数达到上限,则不再完成任务 if (completedTasks >= READING_TASK_LIMIT) { return; } // 完成阅读任务,并将用户已完成的阅读任务数加 1 ops.set(userId, completedTasks + 1); } finally { // 释放分布式锁 lock.unlock(); } } } ``` 在这个例子中,我 ### 回答2: 使用RedissonRedisTemplate可以方便地设计一个Java代码来监控高并发情况下用户完成阅读任务上限后再次完成的场景。 首先,我们可以使用Redisson实现分布式锁,确保在多线程环境下任务的原子性。我们可以通过Redisson获取一个全局的锁,具体实现如下: 1. 创建一个RedissonClient对象: ```java Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); ``` 2. 使用redisson实现分布式锁: ```java RLock lock = redisson.getLock("taskLock"); try{ lock.lock(); // 执行任务逻辑 }finally{ lock.unlock(); } ``` 在执行任务之前获取分布式锁,任务执行完成后释放锁。 接着,我们可以使用RedisTemplate来实现计数器来记录用户阅读任务的完成次数。具体实现如下: 1. 创建一个RedisTemplate对象: ```java RedisConnectionFactory factory = new JedisConnectionFactory(); RedisTemplate<String, String> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); ``` 2. 使用RedisTemplate实现计数器: ```java // 计数器加1 redisTemplate.opsForValue().increment("taskCount:" + userId); // 获取计数器值 Integer count = Integer.valueOf(redisTemplate.opsForValue().get("taskCount:" + userId)); ``` 在用户完成阅读任务后,调用计数器加1的方法,并在判断完成次数是否已达上限时,根据计数器值进行判断。 最后,在高并发情况下,我们可以结合Redisson分布式锁RedisTemplate计数器的功能,实现对用户完成阅读任务上限后再次完成的监控场景。在获取分布式锁时,判断用户之前是否已完成任务上限,如果已完成,则不允许再次完成;如果未完成,则允许用户完成任务并更新计数器值。而在释放锁后,其他线程可以再次去获取锁并判断用户是否已完成任务上限。 以上就是使用RedissonRedisTemplate设计的Java代码来监控高并发情况下用户完成阅读任务上限后再次完成的场景。 ### 回答3: 使用RedissonRedisTemplate,可以设计一个Java代码来监控高并发情况下用户完成阅读任务上限后再次完成的场景。 首先,我们可以使用Redisson提供的`RMap`数据结构来保存用户的阅读任务完成情况。在Redis中,可以创建一个键为`user:read_task_completion`的哈希表,其中存储了每个用户已完成的阅读任务数。键的格式可以根据实际需求进行调整。 在Java代码中,可以使用`RMap`通过用户ID来获取该用户已完成的阅读任务数,并判断是否达到了上限。如果未达到上限,则增加阅读任务完成数,并更新到Redis中。 对于具体的操作,可以使用如下代码实现: ```java import org.redisson.api.RMap; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; public class ReadTaskManager { @Autowired private RedissonClient redissonClient; @Autowired private RedisTemplate<String, Integer> redisTemplate; public void completeReadTask(String userId) { RMap<String, Integer> readTaskCompletionMap = redissonClient.getMap("user:read_task_completion"); // 获取用户已完成的阅读任务数 int completionCount = readTaskCompletionMap.getOrDefault(userId, 0); // 判断是否达到上限 if (completionCount >= 3) { System.out.println("用户已达到阅读任务上限"); return; } // 完成阅读任务 completionCount++; // 更新到Redis中 readTaskCompletionMap.put(userId, completionCount); redisTemplate.opsForHash().put("user:read_task_completion", userId, completionCount); System.out.println("用户完成了阅读任务"); } } ``` 以上代码中,首先通过`redissonClient`获取到`RMap`对象,然后根据用户ID从`RMap`中获取已完成的阅读任务数。然后,根据阅读任务数判断是否达到上限。如果未达到上限,则将阅读任务数+1,并将更新后的阅读任务数存储到Redis中。 需要注意的是,以上代码中依赖于RedissonRedisTemplate,请确保正确配置和注入相关对象。 这样,当在高并发情况下,多个用户同时操作时,通过上述代码可以实现对用户完成阅读任务上限的监控和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值