redis缓存工具Jedis进行跨jvm加锁(分布式应用)

最近使用redis碰到了多个并发处理同一个缓存的情况。在这种情况下需要进行加锁机制。本来想使用java自带的ReadWriteLock进行设置读写锁,这也是上家公司使用的方法。后来经过商讨,给予排除。原因无他,就是java自带的并不能跨jvm进行加锁,意思就是说A服务器上的write锁无法限制B服务器上的同一个方法,也就是说不适用于分布式部署的环境。

后来经过多方面查看资料。最终决定使用redis自身的方法setnx来进行加锁机制。网上有很多关于setnx来进行加锁的方法。不过大部分都会有一个相同的缺陷,就是直接使用setnx加锁、使用del释放锁。这种情况下呢。如果加锁后发生异常导致没有释放锁,则会成为死锁。参考:http://blog.csdn.net/java2000_wl/article/details/8740911

再后来有一种新的思路,将setnx和expire结合使用,使得锁有一个有效期,这样当发生异常,有效期一过可以自动释放锁。这个算是有一些改进,不过由于setnx和expire是两步操作,不具有原子性,如果setnx操作之后发生异常,还是会造成死锁。

然后就考虑有什么办法可以使得setnx和expire操作同步实现并具有原子性。那么转换一下思路,将setnx的value值设置成当前时间过后的某一刻时间(比如1分钟之后),这个是不是就可以间接代替expire操作了。是的,这种方式可以实现。那么现在就是这种方式加上del基本可以实现加锁和解锁(并且可以解因异常为释放的锁)。只不过仍有一些缺陷,因为这种情况会造成竞争关系,参照:https://github.com/huangz1990/redis/commit/18dbaee4f40f435970a09da427b8f45bd26b4072#diff-b643df753e12d0d07a872f91487c957dR34

根据上面链接给出的解决办法(即新算法思路)使用有效期来判断之后不是删除key,而是直接给key赋予新值,使用getset,然后判断得到的值和原来的值是否相等,相等即获得锁。最后提供了手动解锁的方法(即删除key就可以)。下面给出代码:

public boolean lock(String key, long timeout) {
		boolean lockSuccess = false;
		ShardedJedis shardedJedis = pool.getResource();
		try{
			long start = System.currentTimeMillis();
			String lockKey = "lock_"+key;
			do{
				long result = shardedJedis.setnx(lockKey, String.valueOf(System.currentTimeMillis()+LOCKKEY_EXPIRE_TIME*1000+1));
				if(result == 1){
					lockSuccess = true;
					break;
				}else{
					String lockTimeStr = shardedJedis.get(lockKey);
					if(StringUtils.isNumeric(lockTimeStr)){//如果key存在,锁存在
						long lockTime = Long.valueOf(lockTimeStr);
						if(lockTime < System.currentTimeMillis()){//锁已过期
							String originStr = shardedJedis.getSet(lockKey, String.valueOf(System.currentTimeMillis()+LOCKKEY_EXPIRE_TIME*1000+1));
							if(StringUtils.isNoneBlank(originStr)&&originStr.equals(lockTimeStr)){//表明锁由该线程获得
								lockSuccess = true;
								break;
							}
						}
					}
				}
				//如果不等待,则直接返回
				if(timeout == 0){
					break;
				}
				//等待300ms继续加锁
				Thread.sleep(300);
			}while((System.currentTimeMillis()-start) < timeout);

		}catch(Exception e){
			e.printStackTrace();
		}finally{
			...
		}
		return lockSuccess;
	}

	public void unLock(String key) {
		ShardedJedis shardedJedis = pool.getResource();
		try{
			String lockKey = "lock_"+key;
			shardedJedis.del(lockKey);
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			...
		}
	}

大概就这些吧~~~

共勉!

redis缓存工具Jedis进行跨jvm加锁(分布式应用)

时间: 2024-10-13 04:53:25

redis缓存工具Jedis进行跨jvm加锁(分布式应用)的相关文章

Java 使用Redis缓存工具的图文详细方法

开始在 Java 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 Java redis 驱动,且你的机器上能正常使用 Java. (1)Java的安装配置可以参考我们的 Java开发环境配置 (2)安装了 redis 服务: 请参考:Windows环境下使用Redis缓存工具的图文详细方法 或是: 首先你需要下载驱动包,下载 jedis.jar,确保下载最新驱动包. 在你的classpath中包含该驱动包. 一.新建一个javaweb项目. 1. 新建一个Jedis的项目.

Windows环境下使用Redis缓存工具的图文详细方法

网上找了两篇关于Redis的博客,记录下! Java 使用Redis缓存工具的图文详细方法 Windows环境下使用Redis缓存工具的图文详细方法

redis缓存工具类,提供序列化接口

1.序列化工具类 1 package com.qicheshetuan.backend.util; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.ObjectInputStream; 6 import java.io.ObjectOutputStream; 7 8 public class SerializeUtil { 9 10 //序列化 11

Redis Java客户端jedis工具类以及Redis实现的跨jvm的锁

Redis Java客户端jedis工具类以及Redis实现的跨jvm的锁 最近项目中使用redis,学习了一下,client端使用jedis-2.1.0 首先是一个redis实现的跨jvm的lock, 接着是一个简单封装的工具类,也对pipeline处理进行了几个常用的封装 然后是对应Spring的相关配置 Java代码   public class RedisLock { /** 加锁标志 */ public static final String LOCKED = "TRUE";

缓存机制总结(JVM内置缓存机制,MyBatis和Hibernate缓存机制,Redis缓存)

一.JVM内置缓存(值存放在JVM缓存中) 我们可以先了解一下Cookie,Session,和Cache Cookie:当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择都纪录下来.当下次你再光临同一个网站,WEB 服务器会先看看有没有它上次留下的 Cookie 资料,有的话,就会依据 Cookie里的内容来判断使用者,送出特定的网页内容给你.具体来说Cookie机制采用的是在客户端保持状态的方案(保存客户浏览器请求服务器页面

使用maven简单搭建Spring mvc + redis缓存

注:此文参考并整合了网上的文章 <spring缓存机制>:http://blog.csdn.net/sidongxue2/article/details/30516141 <配置 Spring4.0 注解Cache+Redis缓存>:http://blog.csdn.net/ouyhong123/article/details/52162951 <spring整合redis缓存,以注解(@Cacheable.@CachePut.@CacheEvict)形式使用>: ht

使用ZooKeeper实现Java跨JVM的分布式锁(优化构思)

说明:这篇文章是基于 使用ZooKeeper实现Java跨JVM的分布式锁 的,没有阅读的朋友请先阅读前面的文章后在阅读本文. 上一篇文章中介绍了如何使用分布式锁,并且对原来的公平锁进行了扩展,实现了非公平锁,已经能够满足大部分跨进程(JVM)锁的需求了. 问题:我们都知道在单个JVM内部实现锁的机制很方便,Java也提供了很丰富的API可以实现,例如Synchronized关键字, ReentrantLock等等,但是在集群环境中,都是多个JVM协同工作,当需要一些全局锁时就要用到上面介绍的分

Redis缓存系统(一)Java-Jedis操作Redis,基本操作以及 实现对象保存

源代码下载: http://download.csdn.net/detail/jiangtao_st/7623113 1.Maven配置 <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.5.0</version> </dependency> <dependency> <

redis缓存技术

初学redis缓存技术,如果文章写得不好还请谅解 应用环境:win7 实现环境:cmd,eclipse redis缓存技术的特点就在于高效,因为目前涉及的数据量逐渐增多,在对于数据的存储上面和sql以及服务器资源优化上面就来的特别的重要. 而redis可以帮助解决由于数据库压力造成的延迟现象,针对于很少做改变的数据并且经常使用的数据,我们可以一致性加入内存.这样可以一方面减少数据库压力,一方面提高读写效率. 1.第一步在redis官网上面下载对应的压缩包.下载地址:https://github.