Vor kurzem habe ich einige hohe Parallelitätsszenarien bei der Arbeit gestoßen, die das Sperren erfordern, um die Richtigkeit der Geschäftslogik zu gewährleisten, und die Leistung nach dem Sperren sollte nicht zu stark beeinträchtigt werden. Die anfängliche Idee besteht darin, die Daten über Schlüsselwörter wie Zeitstempel und IDs zu sperren und so die Parallelität verschiedener Arten der Datenverarbeitung sicherzustellen. Die von Javas eigene API bereitgestellte Schloss -Granularität ist zu groß, und es ist schwierig, diese Bedürfnisse gleichzeitig zu erfüllen, also habe ich selbst mehrere einfache Erweiterungen geschrieben ...
1. Segmentschloss
Auf die Segmentierungsidee von Concurrenthashmap wird eine bestimmte Anzahl von Schlössern erstellt, und bei der Verwendung wird die entsprechende Sperre entsprechend dem Schlüssel zurückgegeben. Dies ist die einfachste, höchste Leistung und letztendlich die Sperrstrategie unter mehreren Implementierungen an. Der Code ist wie folgt:
/*** Segmentschloss, das System liefert eine bestimmte Anzahl von Originalsperrungen, erhalten Sie die entsprechende Sperre basierend auf dem Hash -Wert des eingehenden Objekts und fügen Sie die Sperre hinzu* Hinweis: Wenn der Hash -Wert des Objekts, das sich verändert, verändert werden kann, kann die Sperre nicht erfolgreich freigegeben werden !!! */public class segmentlock <t> {private Integer -Segmente = 16; // Standardzahl der Segmente private endgültige Hashmap <Integer, Reentrantlock> lockmap = new Hashmap <> (); public segmentLock () {init (null, false); } public segmentlock (Integer zählt, boolean fair) {init (zählt, fair); } private void init (Integer zählt, boolean fair) {if (zählt! = null) {Segmente = zählt; } für (int i = 0; i <Segmente; i ++) {lockmap.put (i, neuer Reentrantlock (fair)); }} public void lock (t key) {reentrantlock lock = lockmap.get ((key.hashCode () >>> 1) % Segmente); lock.lock (); } public void Unlock (t Key) {Reentrantlock lock = lockMap.get ((key.hashCode () >>> 1) % Segmente); lock.unlock (); }}2. Hash Lock
Die zweite Strategie, die basierend auf dem obigen segmentierten Schloss entwickelt wurde, besteht darin, ein echtes feinkörniges Schloss zu erreichen. Jedes Objekt mit einem anderen Hash -Wert kann ein eigenes unabhängiges Schloss erhalten. Wenn der Sperrcode schnell ausgeführt wird, ist die Effizienz etwa 30% langsamer als die Segmentschloss. Wenn es einen langweiligen Betrieb gibt, sollte das Gefühl der Leistung besser sein. Der Code ist wie folgt:
öffentliche Klasse Hashock <t> {private boolean isfair = false; Private Final Segmentlock <T> Segmentlock = new SegmentLock <> (); // Segment Lock Private Final ConcurrentHasMap <t, lockInfo> lockmap = new ConcurrentHasMap <> (); public hashock () {} public hashock (boolean fair) {isfair = fair; } public void Lock (t Key) {lockInfo lockInfo; Segmentlock.lock (Schlüssel); try {lockInfo = lockMap.get (Schlüssel); if (lockInfo == null) {lockInfo = new lockInfo (isfair); lockmap.put (Schlüssel, lockInfo); } else {lockInfo.count.incrementandget (); }} endlich {segmentlock.unlock (key); } lockInfo.lock.lock (); } public void Unlock (T Key) {lockInfo lockInfo = lockMap.get (Schlüssel); if (lockInfo.count.get () == 1) {segmentlock.lock (key); try {if (lockInfo.count.get () == 1) {lockMap.remove (Schlüssel); }} endlich {segmentlock.unlock (key); }} lockInfo.count.decrementandGet (); lockInfo.unlock (); } private statische Klasse LockInfo {public Reentrantlock Lock; public atomicinteger count = neuer atomicinteger (1); private lockinfo (boolean fair) {this.lock = new Reentrantlock (fair); } public void lock () {this.lock.lock (); } public void Unlock () {this.lock.unlock (); }}}3.. Schwache Referenzschloss
Hash-Schlösser sind immer fehlerhaft, da die segmentierten Schlösser eingeführt werden, um die Synchronisation der Scharstellung und Zerstörung zu gewährleisten. Daher wurde ein drittes Schloss geschrieben, um eine bessere Leistung und feinere Schlösser zu suchen. Die Idee dieses Schlosses ist es, mit Hilfe schwacher Referenzen in Java ein Schloss zu erstellen und die Zerstörung des Schlosses an die Müllsammlung von JVM zu übergeben, um zusätzlichen Verbrauch zu vermeiden.
Es ist ein bisschen bedauerlich, dass die Concurrenthashmap als Schlossbehälter verwendet wird, es nicht wirklich von segmentierten Schlössern loswerden kann. Die Leistung dieses Schlosses ist etwa 10% schneller als die von Hashlock. Sperrcode:
/*** Schwache Referenzsperrung, die eine unabhängige Sperrfunktion für jede unabhängige Hash*/öffentliche Klasse WewasHlock <t> {private Concurrenthashmap <t, WeclockRef <t, Reentrantlock >> lockmap = new ConcurrentHasMap <> () bereitstellt; private referencequeue <REENNRANTLOCK> queue = new referencequeue <> (); public Reentrantlock get (t key) {if (lockMap.size ()> 1000) {clearEmptyRef (); } WeapReference <REENNRANTLOCK> lockref = lockMap.get (Schlüssel); Reentrantlock lock = (lockref == null? Null: lockref.get ()); while (lock == null) {lockmap.putiFababSent (Schlüssel, neuer WewlockRef <> (neuer Reentrantlock (), Warteschlange, Schlüssel)); lockRef = lockMap.get (Schlüssel); lock = (lockref == null? null: lockref.get ()); if (lock! = null) {return lock; } clearEmptyRef (); } return lock; } @SuppressWarnings ("Deaktiviert") private void ClearEmptyRef () {Referenz <? erweitert Reentrantlock> Ref; while ((ref = queue.poll ())! erweitert Reentrantlock> Wewlockref = (Wewlockref <t,? REENTRANTLOCK>) REF; lockmap.remove (walchlockref.key); }} private statische endgültige Klasse WeokLockRef <T, K> erweitert WewReference <K> {endgültiger T -Schlüssel; private weclockref (k reference, referencequeue <? super k> q, t key) {super (referent, q); this.key = key; }}}PostScript
Zuerst wollte ich LocksSupport und AQS verwenden, um feinkörnige Schlösser zu implementieren. Wie ich schrieb, stellte ich fest, dass die implementierten Dinge nicht viel anders waren als die in Java Native Locks, also gab ich die Verkapselung von Javas eigenen Schlösser auf, was viel Zeit verschwendete.
Nachdem wir diese feinkörnigen Schlösser implementiert haben, haben wir neue Ideen, z. B. das Senden von Daten an spezielle Threads durch segmentierte Ideen, die die Blockierungszeit einer großen Anzahl von Threads verkürzen und es zukünftiger Erkundungen überlassen ...