いくつかの点で、我々は例えば、文字列に基づいて何かをしたいことがあります。同じのための同時ユーザーの同期、文字列ロックモードのより合理的な利用を実現します。そのため、同じ文字列の場合には、同時動作が許可されていません。私たちは、関係なく、無差別の直接のすべてのロックされている場合と、その後、全体的なパフォーマンスがあまりにも多くをドロップします。
そのため、文字列の様々な、文字列のロックが自然に見える高度なロックロックセグメントであり、それのような多くの利点を獲得。
のでString型の割り当ての変数はこれです:列A =;間違ったイメージを持っているすべては、多くの場合、Stringオブジェクトは不変である「こんにちは世界。」。
量、我々は短期的に、上の手の込んだません。この問題に関する議論は、「」!=「」確立される可能性が高いです。
また、それをロックするため、私たちは皆知っている、同じオブジェクトに対してロックすることです、それは意味のあることだろう。だから、荒いので、私たちは、文字列のロックを使用することができます。
公共ボイド法1(){ = "A"文字列STR1。 同期(STR1){ //物事を同期行う... } } 公共ボイド法2(){ 文字列STR2は= "A"; 同期(STR2){ //同期Bのことを行います... } }
一見すると、これは確かに非常に便利で簡単です。しかし、「」おそらく(Stringは定数プールの文字列変数が等しい同じ時間に保存されているだけで、ほとんどの場合であり、)「A」に等しくない場合、先に述べました。
そこで、我々はやや低い最適化することができます。
公共ボイド法3(){ = "A"文字列STR1。 同期(str1.intern()){ // ...物事を同期さん } } ます。public void法4(){ 文字列STR2 = "A"; 同期(str2.intern()){ //同期Bのことを行います... } }
それでも、それは非常に便利で簡単なに見えますが、原則は一定のプールへStringオブジェクトです。しかし、問題は、それをきれいにする方法については、これらのデータの定数プールがありますか?
とにかく、我々はそれをロックする文字列を達成するために自分で行くことができませんか?
それは確かに可能です!直接コードに!
org.slf4j.Loggerインポート、 インポートorg.slf4j.LoggerFactory; インポートjava.util.concurrent.ConcurrentHashMap; インポートjava.util.concurrent.ConcurrentMap; インポートjava.util.concurrent.CountDownLatch; / ** *文字列の実装ロックに基づきます * / publicクラスStringBasedMutexLock最終{ プライベート静的ロガーロガー=最終LoggerFactory.getLogger(StringBasedMutexLock.class); / ** *文字ロックマネージャたCountDownLatchのそれぞれに文字列を変換する * *すなわち純正ロックにのみ発生同じ条件の文字列の下で同時更新 * * / プライベート静的最終のConcurrentMap <文字列、たCountDownLatch>新新のConcurrentHashMapのlockKeyHolder = <>(); / ** *ベースlockKeyロックされ、同期実行 * @return真*:首尾リリース、偽:リリースが失敗し、他のスレッドが間違えリリースかもしれ * @Param lockKey文字ロック * / パブリック静的な無効ロック(文字列lockKey){ ながら、{(のtryLock(lockKey)!) のtry { logger.debug( "[文字]同時更新ロックロック、{}"、lockKey); blockOnSecondLevelLock (lockKey); }キャッチ(InterruptedExceptionあるE){ にThread.currentThread())(割り込み;. logger.error( "[]の文字が例外割り込みロック:" + lockKey、E); ブレーク; } } } / ** *発売lockKey対応するロックオプションの実行の他のスレッドがその * * @param lockKey相互に排他的である文字列 * / パブリック静的ブールUNLOCK(文字列lockKey){ //最初のロックを削除してから、ロックを解除し、ここに来るためのフォローアップは、同時実行の優先順位につながる、効果なし たCountDownLatch realLock = getAndReleaseLock1(lockKey); releaseSecondLevelLock(realLock); trueに戻る; } / ** *文字を指定してみてください文字列のロック * 文字列を排他的に使用する* @param lockKey * @return真:ロック解除に成功し、偽:ロックされなかった * / {プライベート静的ブールのtryLock(文字列lockKeyを) //ここReentrantLockのを作成した多数のオブジェクトにつながりますそれは? //実際には、この数はちょうどy軸の破壊を作成するために何度も何度も繰り返されることになる、非常に友好的ではないGC、同時外の最大数に等しい (lockKey、新しい新たCountDownLatch(1))== nullが返りlockKeyHolder.putIfAbsentを; } / ** *レベル1レリーズロック(削除)とヘビー級のロックに戻ります * * @param lockKey文字ロック * @return真のロック * / プライベート静的getAndReleaseLock1たCountDownLatch(文字列lockKey){ 戻りlockKeyHolder.remove(lockKey); } / ** * 2つのロック(ロックのエスカレーション) * * @param lockKey列ロック スロー* InterruptedExceptionある中断を@throws * / プライベート静的ボイドblockOnSecondLevelLock(文字列lockKey)がスローInterruptedExceptionある{ たCountDownLatch realLock = getRealLockByKey(lockKey); //この場合はヌル記載されているロックが削除された、レース次に IF(realLock = NULL!){ realLock.await(); } } / ** * 2は、ロック解除ロック(必要な場合) * * @param realLockロックの例 * / プライベート静的ボイドreleaseSecondLevelLock(たCountDownLatch realLock){ realLock.countDown(); } / ** * LOCKキーを取得することによってインスタンスを対応する * * @paramは、文字列をロックlockKey *例えばロック@return * / プライベート静的getRealLockByKeyたCountDownLatch(文字列lockKeyは){ ; lockKeyHolder.get(lockKey)を返します } }
使用に際しては、単にlockKeyを渡すことができます。
ロック// StringBasedMutexLock.lock(linkKeyを); //ロック解除 StringBasedMutexLock.unlock(linkKey)を、
それはこれを良い何しているのですか?
1. ConcurrentHashMapの実装のロック取得が、パフォーマンスは良好であり、
2各文字列は、メモリオーバーフローを引き起こすことはありません削除を完了するために使用した後、ロックに対応し、
3は外部ツールとして使用することができる、簡単にアクセスできるサービスコードなし、同期のように、コードのセクション全体をラップする必要があります。
不十分な?
1. ConcurrentHashMapの実装のロック取得が、パフォーマンスは良好であり、
2各文字列は、メモリオーバーフローを引き起こすことはありません削除を完了するために使用した後、ロックに対応し、
3は外部ツールとして使用することができる、簡単にアクセスできるサービスコードコード全体を包むために必要として、同期とせず;
4.この記事は、単なる文字列のロックを達成するために見せたい、このロックは、分散シナリオでの並列処理には適していません。
拡張:あなたはセキュリティスレッドに大きな前提同時並行シーンの小さな確率を確保する方法を、文字列のロックを使用しない場合は?
私たちは、CASを操作するクラス原子を使用することができ、CAS効率が比較的高いことを知っています。
例えば、我々は、スレッドの安全性を確保するために、このフィールドを操作し、ステータスフィールドを追加します。
/ ** *運転状態 * * 4:削除、1:キューに入れられている、0:通常動作なし * / のAtomicIntegerののAtomicIntegerのプライベート過渡揮発性runningStatus新しい新=(0); 状態//更新を取得する: 公共method5ボイド(){ のAtomicIntegerのrunningStatus link.getRunningStatus =(); //プロセスデータを待って削除される (!runningStatus.compareAndSet(0 ,. 1)){IF //別の1の完全なスレッドが待機を削除 // 2。識別更新削除 // 3.データが論理的に再実行 ロングlockStartTime =にSystem.currentTimeMillis(); ロングmaxLockTime = 10 * 1000; (!runningStatus.compareAndSet(0 ,. 1))、一方{ { - (lockStartTime> maxLockTimeのSystem.currentTimeMillis())IF ロガー.ERROR(「データが更新され、削除されていない、リターン」); ブレーク; } } runningStatus.compareAndSet(1、0); 新しいのRuntimeExceptionをスロー( "数据正在更新、重新运行:" + link.getLinkKey()+リンク)。 } {しようと //同期のことを行う } 最後に{ runningStatus.compareAndSet(1、0); } } 公共ボイドmethod6(){ のAtomicInteger runningStatus = link.getRunningStatus()。 場合(!runningStatus.compareAndSet(0,4)){ 返します。 } {しようと //同期に物事を行います } キャッチ(例外E){ logger.error( "同時更新の例外:"、Eを); } 最後に{ runningStatus.compareAndSetを(4、0); } }
実際のテストダウンは、CASのパフォーマンスが同期ロック良いことしたいのパフォーマンスよりも優れています。もちろん、私たちに対する同時の数は、我々だけでこれらのまれなケースでは、スレッドの安全性を確保したい、いくつかあります。だから、実際には、より良いです。
しつこい:落ち着い。