Java分散ロックを実装する方法
1. 分散ロックの概要
単一マシンのマルチスレッド: Java では通常、ReetrantLock クラスや synchronized キーワードなどのローカル ロックを使用して、JVM プロセス内の複数のスレッドを制御し、ローカル共有にアクセスします。
# 分散システム: 通常、さまざまなサービス/クライアントは別個の JVM プロセスで実行されます。複数の JVM プロセスが同じリソースを共有する場合、ローカル ロックを使用してリソースへの相互排他的アクセスを実現する方法はありません。このようにして、分散ロックが誕生しました。
例: システムの注文サービスのコピーが合計 3 つ展開され、すべてが外部にサービスを提供します。ユーザーは注文前に在庫を確認する必要があるため、過剰販売を防ぐために、在庫確認操作への同期アクセスを実現するためにロックが必要です。注文サービスは別の JVM プロセスに配置されているため、この場合、ローカル ロックは正しく機能しません。分散ロックを使用する必要があります。これにより、複数のスレッドが同じ JVM プロセスに存在しない場合でも、同じロックを取得でき、それによって共有リソースへの相互排他的アクセスが実現されます。
最も基本的な分散ロックは次の条件を満たす必要があります:
相互排他: いつでも、ロックは次のユーザーのみが保持できます。 1 つのスレッド ホールド;
高可用性: ロック サービスは高可用性です。さらに、ロックを解放するためのクライアントのコード ロジックに問題がある場合でも、ロックは最終的に解放され、共有リソースへの他のスレッドのアクセスには影響しません。
リエントラント: ノードはロックを取得した後、再度ロックを取得できます。
2. Redis に基づいた分散ロックの実装
1. Redis に基づいた最も単純な分散ロックの実装方法
ローカル ロックかどうかまたは 分散ロックの核心は == 「相互排他」 == にあります。
Redis では、SETNX
コマンドを使用して相互排他を実現できます。 SETNX
つまり、SET if Not eXists (Java の setIfAbsent メソッドに相当) キーが存在しない場合は、キーの値が設定されます。キーがすでに存在する場合、SETNX は何も行いません。
> SETNX lockKey uniqueValue
(integer) 1
> SETNX lockKey uniqueValue
(integer) 0
ロックを解除するには、 DEL コマンドで対応するキーを直接削除します
> DEL lockKey
(整数) 1
他のロックを誤って削除しないように、ここをお勧めしますLuaスクリプトを使用して、キーに対応する値(ユニーク値)で判定します。
Lua スクリプトは、ロック解除操作の原子性を確保するために選択されています。 Redis は Lua スクリプトをアトミックな方法で実行できるため、ロック解放操作のアトミック性が保証されます。
// 释放锁时,先比较锁对应的 value 值是否相等,避免锁的误释放 if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
これは最も単純な Redis 分散ロックの実装です。実装方法は比較的単純で、パフォーマンスは非常に効率的です。ただし、この方法で分散ロックを実装するにはいくつかの問題があります。たとえば、ロックを解放するロジックが突然ハングアップするなど、アプリケーションで何らかの問題が発生した場合、ロックが解放されず、他のスレッド/プロセスが共有リソースにアクセスできなくなる可能性があります。
2. ロックの有効期限を設定する理由
主にロックが解放されないようにするためです
127.0.0.1:6379> SET lockKey uniqueValue EX 3 NX
OK
lockKey: ロック名;
uniqueValue: ロックを一意に識別できるランダムな文字列。
NX: SET は、lockKey に対応するキー値が存在しない場合にのみ成功します;
EX: 有効期限の設定 (秒 ) EX 3 は、このロックの自動有効期限が 3 秒であることを示します。 EX に対応するのは PX (ミリ秒単位) で、どちらも有効期限の設定です。
指定されたキーの値と有効期限の設定がアトミックな操作であることを確認してください。 ! !そうしないと、ロックが解除できないという問題が依然として発生する可能性があります。
このソリューションには抜け穴もあります:
共有リソースの操作時間が有効期限よりも長い場合、ロックの早期期限切れの問題が発生します。分散ロックが発生する 直接的な障害
ロック タイムアウトの設定が長すぎると、パフォーマンスに影響します
3。ロックの正常な更新を実現します
Redisson は、複数の分散ロックの実装だけでなく、すぐに使える多くの機能を提供するオープン ソースの Java 言語 Redis クライアントです。さらに、Redisson は、Redis スタンドアロン、Redis Sentinel、Redis Cluster などの複数のデプロイメント アーキテクチャもサポートしています。
Redisson の分散ロックには自動更新メカニズムが備わっています。使い方は非常に簡単で、原理も比較的単純です。ロックの監視と更新に特別に使用される Watch Dog が提供されます。共有リソースの実行が完了していない場合、Watch Dog はロックの有効期限を継続的に延長して、タイムアウトによってロックが解放されないようにします。
使用方式举例:
// 1.获取指定的分布式锁对象
RLock lock = redisson.getLock("lock");
// 2.拿锁且不设置锁超时时间,具备 Watch Dog 自动续期机制
lock.lock();
// 3.执行业务
...
// 4.释放锁
lock.unlock();
只有未指定锁超时时间,才会使用到 Watch Dog 自动续期机制。
// 手动给锁设置过期时间,不具备 Watch Dog 自动续期机制 lock.lock(10, TimeUnit.SECONDS);
总的来说就是使用Redisson,它带有自动的续期机制
4. 如何实现可重入锁
所谓可重入锁指的是在一个线程中可以多次获取同一把锁,比如一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法即可重入 ,而无需重新获得锁。像 Java 中的 synchronized 和 ReentrantLock 都属于可重入锁。
可重入分布式锁的实现核心思路是线程在获取锁的时候判断是否为自己的锁,如果是的话,就不用再重新获取了。为此,我们可以为每个锁关联一个可重入计数器和一个占有它的线程。当可重入计数器大于 0 时,则锁被占有,需要判断占有该锁的线程和请求获取锁的线程是否为同一个。
以上がJava分散ロックを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック









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

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

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

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。
