ホームページ Java &#&チュートリアル Java は Redis に基づいて分散ロックを実装します

Java は Redis に基づいて分散ロックを実装します

Aug 28, 2019 pm 04:12 PM
java

分散ロックは、Zookeeper、Redis など、さまざまな方法で実装できます。いずれの場合でも、基本原則は同じです。つまり、ロックを表すために状態値が使用され、ロックの占有と解放は状態値によって識別されます。

Java は Redis に基づいて分散ロックを実装します

1. Redis が分散ロックを簡単に実装できる理由

1. Redis は単一プロセス、単一スレッド モードであり、キュー このモードは同時アクセスをシリアル アクセスに変換し、複数のクライアントの Redis への接続間に競合はありません。

2. Redis の SETNX コマンドを使用すると、簡単に分散ロックを実装できます。

setNX(存在しない場合はSET)

構文: SETNXキー値

戻り値: 設定が成功した場合は1が返され、設定が失敗した場合は0が返されます。戻ってきた。

キーが存在しない場合にのみ、キーの値を value に設定し、1 を返します。指定されたキーがすでに存在する場合、SETNX は何も実行せず、0 を返します。

要約すると、setnx の戻り値を使用してロックが取得されているかどうかを判断できます。Redis はシングルスレッドであるため、同時アクセスについて心配する必要はありません。1 を返した場合、ロックが取得され、0 が返されます。取得されませんでした。業務が終了したらロックを解除する必要がありますが、ロック解除のロジックは非常に単純で、前回設定したキーを削除し、次回からキーを設定することでロックを取得できるようになります。

2. 分散ロックの実装

分散ロックは Redis 独自の関数 setNX を通じて実装できることはすでにわかっています。具体的な実装手順は次のとおりです。

CentOS7 Linux 仮想マシンに Redis サービスをインストールしました。IP アドレスは 192.168.246.130、サービス ポートは 6379 です。

次は、redis を介して分散ロックを実装する Java の例です:

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
操作执行完成,释放锁
ログイン後にコピー

上記のコードは単一のアプリケーション内にありますが、複数のスレッドでテストされましたが、分散環境でロックを取得するために複数のアプリケーションと複数のスレッドが使用された場合でも、結果は依然として正しいです。

3. デッドロック問題を解決する

前のコード例は、原理を説明するための単なるテスト コードです。例自体は非常に単純なので、次のようなものがあります。いくつかの考慮されていない側面があります。例えば、ロック取得後、業務実行中に環境問題が発生してRedisとの接続が切断され、finallyブロックでロックが解除できず、ロック取得を待っていた他のスレッドが無限に待機してしまう、といった場合です。デッドロック現象が起こるのです。

解決策:

Redis でロックの有効期限を設定できるため、ロックを解放できない場合でも、一定の時間が経過すると自動的にロックが解放されます。期間。

コードに関しては、ロックを取得した後に次のコードを try ステートメント ブロックに追加するだけです:

jedis.expire(key, 10); //这里给锁设置10秒的过期时间
ログイン後にコピー

より良い解決策:

1 つの解決策はあまり良くありません。ビジネス オペレーションの処理時間が非常に長く、設定された有効期限を超えると、ロックが自動的に解放され、その後、finally ブロックでロックを解放する操作が実行されると、ロックが解除されてしまいます。スレッドが保持しているロックにより、他のスレッドが保持しているロックが解放されるため、同時実行性の問題が発生します。したがって、ロックを解除するときにロックの有効期限が切れているかどうかを判断し、期限が切れている場合は再度ロックを解除する必要はありません。

コード内で、ロックを取得した後の操作を次のコードに変更します:

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

以上がJava は Redis に基づいて分散ロックを実装しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの平方根 Javaの平方根 Aug 30, 2024 pm 04:26 PM

Java の平方根のガイド。ここでは、Java で平方根がどのように機能するかを、例とそのコード実装をそれぞれ示して説明します。

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのアームストロング数 Javaのアームストロング数 Aug 30, 2024 pm 04:26 PM

Java のアームストロング番号に関するガイド。ここでは、Java でのアームストロング数の概要とコードの一部について説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

See all articles