1. Longadder
Es wird ähnlich wie Atomiclong verwendet, hat aber eine bessere Leistung als Atomiclong.
Longadder und Atomiclong verwenden beide Atomoperationen, um die Leistung zu verbessern. Longader führt jedoch eine Hotspot -Trennung durch, basierend auf Atomiclong. Die Trennung der Hotspot ähnelt der Reduzierung der Sperrpartikelgröße im gesperrten Betrieb und trennt ein Schloss in mehrere Schlösser, um die Leistung zu verbessern. Bei lock-freien können ähnliche Methoden verwendet werden, um die Erfolgsrate von CAS zu erhöhen, wodurch die Leistung verbessert wird.
Langlastschema:
Die Implementierungsmethode von Atomiclong besteht darin, dass es im Inneren eine Wertvariable gibt. Wenn mehrere Fäden selbsterziehend und selbstverletzt sind, werden sie alle über die Anweisungen der Maschinenanweisungen betrieben, um die Atomizität der Parallelität zu gewährleisten. Der einzige Grund, der die Effizienz von Atomiclong einschränkt, ist eine hohe Parallelität. Eine hohe Parallelität bedeutet, dass die CAS eine höhere Wahrscheinlichkeit eines Versagens hat, mehr Wiederholungszeiten und je mehr Fäden wiederholt, desto höher ist die Wahrscheinlichkeit eines Misserfolgs von CAS, der zu einem Teufelskreis wird, und die Effizienz von Atomiclong wird verringert.
Longadder wird einen Wert in mehrere Zellen aufteilt und alle Zellen zum Wert addiert. Daher müssen Sie beim Hinzufügen und Subtrahieren von Longaden nur in verschiedenen Zellen arbeiten. Verschiedene Fäden führen CAS -Operationen in verschiedenen Zellen aus. Natürlich ist die Erfolgsrate von CAS hoch (vorstellen Sie 3+2+1 = 6, ein Faden 3+1, der andere Faden 2+1 und schließlich 8, Longadder hat keine API für Multiplikation und Teilung).
Wenn die Parallelitätszahl jedoch nicht sehr hoch ist, muss auch in mehreren Zellen die Aufrechterhaltung der Zelle und die Summierung erforderlich sind, was nicht so effizient ist wie die Implementierung von Atomiclong. Longadder benutzte eine clevere Möglichkeit, dieses Problem zu lösen.
In der anfänglichen Situation sind Longadder und Atomiclong gleich. Nur wenn CAS ausfällt, wird der Wert in Zellen aufgeteilt. Jedes Mal, wenn das Versagen vorgenommen wird, wird die Anzahl der Zellen erhöht. Dies ist auch effizient bei geringer Parallelität. Bei hoher Parallelität schlägt diese "adaptive" Verarbeitungsmethode nach Erreichen einer bestimmten Anzahl von Zellen nicht aus, und die Effizienz wird erheblich verbessert.
Longader ist eine Strategie, um Platz für Zeit auszutauschen.
2. komplettfuture
Implementieren Sie die CompletionStage -Schnittstelle (mehr als 40 Methoden), von denen die meisten in der funktionalen Programmierung verwendet werden. Und Unterstützung von Streaming -Anrufen
CompleteFuture ist eine verbesserte Version der Zukunft in Java 8
Einfache Implementierung:
importieren java.util.concurrent.comPletableFuture; öffentliche Klasse Askthread Implements Runnable {CompletenableFuture <Integer> re = null; public Askthread (komplettableFuture <Ganzzahl> re) {this.re = re; } @Override public void run () {int myre = 0; try {myre = re.get () * re.get (); } catch (Ausnahme e) {} system.out.println (myre); } public static void main (String [] args) löst InterruptedException aus. neuer Thread (neuer Askthread (Zukunft)). start (); // einen Langzeitberechnungsprozess-Thread simulieren. Sleep (1000); // das Fertigstellungsergebnis für FutureC. }} Das am stärksten kritisierte an Zukunft ist, dass Sie warten müssen und überprüfen müssen, ob die Aufgabe selbst erledigt wurde. In Zukunft ist die Zeit, die die Aufgabe erledigt, unkontrollierbar. Die größte Verbesserung der vollständigen Future besteht darin, dass die Zeit für die Abschluss der Aufgaben ebenfalls geöffnet ist.
Future.com plete (60);
Wird verwendet, um die Abschlusszeit festzulegen.
Asynchrone Ausführung von vollständiger Future:
public static Integer Calc (Ganzzahl para) {try {// Simulieren Sie einen langen Ausführungs -Thread.sleep (1000); } catch (InterruptedException e) {} return para * para; } public static void main (String [] args) löst InterruptedException aus, executionException {endgültige Vervollständigungsabläufe <Ganzzahl> Future = CompletenableFuture .Supplyasync (() -> Calc (50)); System.out.println (Future.get ()); } Streaming Call of CompleteableFuture: public statische Ganzzahl Calc (Ganzzahl Abs.) {Try {// Simulieren Sie einen langen Ausführungs -Thread.Sleep (1000); } catch (InterruptedException e) {} return para * para; } public static void main (String [] args) löst InterruptedException, ExecutionException aus {vervollständigungsableFuture <void> fu = komplettableFuture .Supplyasync (() -> Calc (50)) .Thenapply ((i) -> Integer .Denaccept (System.out :: println); fu.get (); }Kombinieren Sie mehrere Vervollständigungsfuturen:
public static Integer Calc (Ganzzahl para) {return para / 2; } public static void main (String [] args) löst InterruptedException, ExecutionException aus. "/" ") .Denaccept (System.out :: println); fu.get (); } Diese Beispiele konzentrieren sich mehr auf einige neue Funktionen von Java 8. Hier sind einige Beispiele, um die Funktionen zu veranschaulichen, sodass ich nicht eingehend damit eingehen werde.
CompleteFuture hat wenig mit Leistung zu tun, ist aber wichtiger, um die funktionale Programmierung und Verbesserung von Funktionen zu unterstützen. Natürlich ist die Einstellung der Abschlusszeit ein Highlight.
3. Stampedlock
Im vorherigen Artikel wurde nur die Trennung der Schloss erwähnt, und die wichtige Implementierung der Sperrtrennung ist ReadWriteLock. Stampedlock ist eine Verbesserung von ReadWriteLock. Der Unterschied zwischen Stampedlock und ReadWriteLock besteht darin, dass Stampedlock der Ansicht ist, dass das Lesen nicht blockieren sollte, und Stampedlock glaubt, dass beim Lesen und Schreiben das Lesen erneut gelesen werden sollte, anstatt den Schreib -Thread nicht zu schreiben. Dieses Design löst das Problem des Schreibens von Thread -Hunger, wenn Sie mehr lesen und weniger schreiben.
Stampedlock ist also eine Verbesserung, die dazu neigt, Threads zu schreiben.
Stampedlock -Beispiel:
import Java.util.concurrent private final stampedlock sl = neuer stampedlock (); void Move (Doppel -Deltax, Doppeldeltay) {// Eine ausschließlich gesperrte Methode Long stempel = sl.writeLock (); try {x += deltax; y += deltay; } endlich {sl.unlockwrite (stempel); }} doppelte Abstandfromorigin () {// Eine schreibgeschützte Methode long stempel = sl.tryoptimisticread (); double currentX = x, currenty = y; if (! try {currentX = x; Currenty = y; } endlich {sl.unlockread (stempel); }} return Math.sqrt (currentX * currentX + currenty * currenty); }}Der obige Code simuliert den Schreibbeauftrag und den Lesen von Thread. Stampedlock überprüft, ob es sich gegenseitig entsprechend dem Stempel gegenseitig ausschließt. Wenn Sie einmal einen Stempel schreiben, erhöht er einen bestimmten Wert.
tryoptimisticread ()
Es ist die Situation, in der das Lesen und Schreiben nicht wie erwähnt sich gegenseitig ausschließt.
Jedes Mal, wenn Sie einen Thread lesen, werden Sie zuerst ein Urteil fällen
if (! Sl.Validate (Stempel))
Bei Validate wird zunächst prüft, ob ein Schreib -Thread geschrieben wird, und dann festzustellen, ob der Eingabwert mit dem aktuellen Stempel übereinstimmt, dh bestimmen Sie, ob der Lese -Thread die neuesten Daten liest.
Wenn ein Schreib -Thread geschrieben wird oder der Stempelwert unterschiedlich ist, schlägt die Rückgabe fehl.
Wenn das Urteil fehlschlägt, können Sie natürlich versuchen, es wiederholt zu lesen. Im Beispielcode darf es nicht wiederholt versuchen, es zu lesen, sondern verwendet stattdessen das Optimismus -Sperre, um in gewöhnliche Lesesperrungen zu entgeführt, um es zu lesen. Diese Situation ist eine pessimistische Lesemethode.
stempel = sl.readlock ();
Vorstellung von Stampedlock Implementierung:
CLH Spin Lock: Wenn die Sperranwendung fehlschlägt, wird der Lesefaden nicht sofort suspendiert. Eine wartende Thread -Warteschlange wird im Schloss gewartet. In dieser Warteschlange werden alle Threads, die für Sperren gelten, aber keine erfolgreichen Threads angewendet werden. Jeder Knoten (ein Knoten repräsentiert einen Thread) speichert ein gesperrtes Bit, um festzustellen, ob der aktuelle Thread die Sperre freigegeben hat. Wenn ein Faden versucht, ein Schloss zu erwerben, erhält er den Heckknoten der aktuellen Warteschlange als Vorgängerknoten. Verwenden Sie Codes wie Folgendes, um festzustellen
while (pred.locked) {
}
Diese Schleife soll darauf warten, dass der vorherige Knoten das Schloss freigibt, damit der aktuelle Thread nicht vom Betriebssystem ausgesetzt wird, wodurch die Leistung verbessert wird.
Natürlich wird es keine endlosen Drehungen geben, und der Faden wird nach mehreren Drehungen suspendiert.