搜索
首页Javajava教程Java基于Redis实现分布式锁

Java基于Redis实现分布式锁

Aug 28, 2019 pm 04:12 PM
java

分布式锁可以基于很多种方式实现,比如zookeeper、redis...。不管哪种方式,他的基本原理是不变的:用一个状态值表示锁,对锁的占用和释放通过状态值来标识。

Java基于Redis实现分布式锁

一、为什么Redis可以方便地实现分布式锁

1、Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。

2、Redis的SETNX命令可以方便的实现分布式锁。

setNX(SET if Not eXists)

语法:SETNX key value

返回值:设置成功,返回 1 ;设置失败,返回 0 。

当且仅当 key 不存在时将 key 的值设为 value,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。

综上所述,可以通过setnx的返回值来判断是否获取到锁,并且不用担心并发访问的问题,因为Redis是单线程的,所以如果返回1则获取到锁,返回0则没获取到。当业务操作执行完后,一定要释放锁,释放锁的逻辑很简单,就是把之前设置的key删除掉即可,这样下次又可以通过setnx该key获取到锁了。

二、分布式锁实现

我们已经知道可以通过Redis自带的函数setNX来实现分布式锁,具体实现步骤如下。

我在一台CentOS7的linux虚拟机中安装了Redis服务,ip地址为:192.168.246.130,服务端口为:6379。

下面是java通过redis实现分布式锁的例子:

import redis.clients.jedis.Jedis;
public class RedisLock {
	//锁的key
	private static final String key = "DistributedRedisLock";
	private static Integer count = 0;
	public static void main(String[] args) {
		for(int i=0;i<1000;i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					//获取Redis连接
					Jedis jedis = new Jedis("192.168.246.130", 6379);
					try{
						while(true){
							//获取锁
							if(jedis.setnx(key, Thread.currentThread().getName()) == 1){
								try{
									System.out.println("线程("+Thread.currentThread().getName()+")获取到锁,开始执行操作");
									count++;
									System.out.println(count);
									break;
								}finally{
									System.out.println("操作执行完成,释放锁");
									//操作执行完一定要释放锁,所以在finally块中执行
									jedis.del(key);
								}
							}else{
								//返回的不是1,说明已经有某个线程获取到了锁
								try {
									//等待100毫秒之后重试
									Thread.sleep(100l);
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
							}
						}
					}catch(Exception e){
						e.printStackTrace();
					}finally{
						//释放Redis连接
						jedis.disconnect();
					}
				}
			}).start();
		}
	}
}

上述代码的输出结果为:

线程(Thread-320)获取到锁,开始执行操作
1
操作执行完成,释放锁
线程(Thread-463)获取到锁,开始执行操作
2
操作执行完成,释放锁
线程(Thread-997)获取到锁,开始执行操作
3
操作执行完成,释放锁
...
线程(Thread-409)获取到锁,开始执行操作
998
操作执行完成,释放锁
线程(Thread-742)获取到锁,开始执行操作
999
操作执行完成,释放锁
线程(Thread-286)获取到锁,开始执行操作
1000
操作执行完成,释放锁

上述代码虽然是在单应用多线程情况下测试的,但即便是在分布式环境下多应用多线程去获取锁,结果依然是正确的。

三、解决死锁问题

之前的例子代码只是测试代码,只是为了说明原理,例子本身很简单,所以有一些考虑不周的地方。比如当获取到锁之后在业务操作执行过程中发生了环境问题导致断开了和Redis的连接,那就无法在finally块中释放锁,导致其他等待获取锁的线程无限等待下去,也就是发生了死锁现象。

解决方式:

可以在Redis中给锁设置一个过期时间,这样即便无法释放锁,锁也能在一段时间后自动释放。

代码上只需要在获取到锁之后在try语句块中加入如下代码:

jedis.expire(key, 10); //这里给锁设置10秒的过期时间

更妥善的解决方式:

第一个解决方式并不是很好,因为当业务操作处理时间很长,超过了设置的过期时间,那锁就自动释放了,然后再执行finally块中释放锁的操作时,这个锁可能已经被其他线程所持有,会导致把其他线程持有的锁给释放了,从而导致并发问题。所以更妥善一点的方式是在释放锁时判断一下锁是否已经过期,如果已经过期就不用再释放了。

代码上把获取到锁之后的操作改为如下代码:

long start = System.currentTimeMillis(); //获取起始时间毫秒数
try{
  jedis.expire(key, 10);
  ...
}finally{
  ...
  if(System.currentTimeMillis() < start+10*1000){
     //如果之前设置的锁还未过期,则释放掉
     jedis.del(key);
  }
}

以上是Java基于Redis实现分布式锁的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:CSDN。如有侵权,请联系admin@php.cn删除
Java仍然是基于新功能的好语言吗?Java仍然是基于新功能的好语言吗?May 12, 2025 am 12:12 AM

Javaremainsagoodlanguageduetoitscontinuousevolutionandrobustecosystem.1)Lambdaexpressionsenhancecodereadabilityandenablefunctionalprogramming.2)Streamsallowforefficientdataprocessing,particularlywithlargedatasets.3)ThemodularsystemintroducedinJava9im

是什么使Java很棒?关键特征和好处是什么使Java很棒?关键特征和好处May 12, 2025 am 12:11 AM

Javaisgreatduetoitsplatformindependence,robustOOPsupport,extensivelibraries,andstrongcommunity.1)PlatformindependenceviaJVMallowscodetorunonvariousplatforms.2)OOPfeatureslikeencapsulation,inheritance,andpolymorphismenablemodularandscalablecode.3)Rich

前5个Java功能:示例和解释前5个Java功能:示例和解释May 12, 2025 am 12:09 AM

Java的五大特色是多态性、Lambda表达式、StreamsAPI、泛型和异常处理。1.多态性让不同类的对象可以作为共同基类的对象使用。2.Lambda表达式使代码更简洁,特别适合处理集合和流。3.StreamsAPI高效处理大数据集,支持声明式操作。4.泛型提供类型安全和重用性,编译时捕获类型错误。5.异常处理帮助优雅处理错误,编写可靠软件。

Java的最高功能如何影响性能和可伸缩性?Java的最高功能如何影响性能和可伸缩性?May 12, 2025 am 12:08 AM

java'stopfeatureSnificallyEnhanceItsperFormanCeanDscalability.1)对象 - 方向 - incipleslike-polymormormormormormormormormormormormormorableablefleandibleandscalablecode.2)garbageCollectionAutoctionAutoctionAutoctionAutoctionAutoctionautomorymanatesmemorymanateMmanateMmanateMmanagementButCancausElatenceiss.3)

JVM内部:深入Java虚拟机JVM内部:深入Java虚拟机May 12, 2025 am 12:07 AM

JVM的核心组件包括ClassLoader、RuntimeDataArea和ExecutionEngine。1)ClassLoader负责加载、链接和初始化类和接口。2)RuntimeDataArea包含MethodArea、Heap、Stack、PCRegister和NativeMethodStacks。3)ExecutionEngine由Interpreter、JITCompiler和GarbageCollector组成,负责bytecode的执行和优化。

什么是使Java安全安全的功能?什么是使Java安全安全的功能?May 11, 2025 am 12:07 AM

Java'ssafetyandsecurityarebolsteredby:1)strongtyping,whichpreventstype-relatederrors;2)automaticmemorymanagementviagarbagecollection,reducingmemory-relatedvulnerabilities;3)sandboxing,isolatingcodefromthesystem;and4)robustexceptionhandling,ensuringgr

必不可少的Java功能:增强您的编码技巧必不可少的Java功能:增强您的编码技巧May 11, 2025 am 12:07 AM

javaoffersseveralkeyfeaturesthatenhancecodingskills:1)对象 - 方向 - 方向上的贝利奥洛夫夫人 - 启动worldentities

JVM最完整的指南JVM最完整的指南May 11, 2025 am 12:06 AM

thejvmisacrucialcomponentthatrunsjavacodebytranslatingitolachine特定建筑,影响性能,安全性和便携性。1)theclassloaderloader,links andinitializesClasses.2)executionEccutionEngineExecutionEngineExecutionEngineExecuteByteCuteByteCuteByteCuteBytecuteBytecuteByteCuteByteCuteByteCuteBytecuteByteCodeNinstRonctientions.3)Memo.3)Memo

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境