1. Longadder
Il est utilisé de la même manière qu'Atomiclong, mais a de meilleures performances qu'Atomiclong.
Longadder et Atomiclong utilisent tous deux des opérations atomiques pour améliorer les performances. Cependant, Longadder effectue une séparation des points chauds sur la base d'Atomiclong. La séparation des points chauds est similaire à la réduction de la taille des particules de verrouillage en fonctionnement verrouillé, séparant une serrure en plusieurs verrous pour améliorer les performances. Dans des méthodes sans serrures, des méthodes similaires peuvent être utilisées pour augmenter le taux de réussite des CAS, améliorant ainsi les performances.
Schéma Longadder:
La méthode d'implémentation d'Atomiclong est qu'il existe une variable de valeur à l'intérieur. Lorsque plusieurs threads sont auto-croissants et se décolleront, ils sont tous opérés à partir du niveau d'instructions de la machine via les instructions CAS pour assurer l'atomicité de la concurrence. La seule raison qui restreint l'efficacité d'Atomiclong est une concurrence élevée. Une concurrence élevée signifie que le CAS a des chances de défaillance plus élevées, plus de temps de réessayer, et plus il y a de threads réessayent, plus les chances de défaillance de la CAS devient élevée, ce qui devient un cercle vicieux, et l'efficacité de l'atomique est réduite.
Longadder divisera une valeur en plusieurs cellules et additionnera toutes les cellules à la valeur. Par conséquent, lors de l'ajout et de la soustraction de Longadder, il vous suffit de fonctionner sur différentes cellules. Différents threads effectuent des opérations CAS sur différentes cellules. Bien sûr, le taux de réussite de CAS est élevé (imaginez 3 + 2 + 1 = 6, un thread 3 + 1, l'autre thread 2 + 1, et enfin 8, Longadder n'a pas d'API pour la multiplication et la division).
Cependant, lorsque le nombre de concurrence n'est pas très élevé, la division en plusieurs cellules nécessite également le maintien de la cellule et la sommation, ce qui n'est pas aussi efficace que la mise en œuvre d'Atomiclong. Longadder a utilisé une façon intelligente de résoudre ce problème.
Dans la situation initiale, Longadder et Atomiclong sont les mêmes. Ce n'est que lorsque le CAS échoue, la valeur sera divisée en cellules. Chaque fois que la défaillance est effectuée, le nombre de cellules sera augmenté. Ceci est également efficace dans une faible concurrence. Dans une concurrence élevée, cette méthode de traitement "adaptative" n'échouera pas après avoir atteint un certain nombre de cellules, et l'efficacité sera considérablement améliorée.
Longadder est une stratégie d'échange d'espace pour le temps.
2. Fotorfuture
Implémentez l'interface EXCELIONSTAGE (plus de 40 méthodes), dont la plupart sont utilisées dans la programmation fonctionnelle. Et prendre en charge les appels en streaming
CompleteFuture est une version améliorée de Future dans Java 8
Implémentation simple:
Importer java.util.concurrent.completablefuture; public class askthread implémente runnable {completablefuture <nulger> re = null; Public Askthread (completableFuture <Integer> re) {this.re = re; } @Override public void run () {int myre = 0; essayez {myre = re.get () * re.get (); } catch (exception e) {} System.out.println (myre); } public static void main (String [] args) lève InterruptedException {final terminablefuture <nouger> futur = new EXCHETABLEFUTURE <NTEGER> (); nouveau thread (new Askthread (futur)). start (); // simulez un thread de processus de calcul à long terme.Sleep (1000); // informer le résultat de l'achèvement futur.compte (60); }} La chose la plus critiquée à propos de l'avenir est que vous devez attendre et vérifier si la tâche a été accomplie par vous-même. À l'avenir, le temps de terminer la tâche est incontrôlable. La plus grande amélioration de la fonction complète est que le temps d'achèvement des tâches est également ouvert.
Future.Comptete (60);
Utilisé pour définir le temps d'achèvement.
Exécution asynchrone de la transition complète:
public static entier calc (entier para) {try {// simule un thread d'exécution long.sleep (1000); } catch (InterruptedException e) {} return para * para; } public static void main (String [] args) lève InterruptedException, ExecutionException {final EXCHETABLEFUTURE <NTEGER> futur = completsableFuture .SupplyAsync (() -> calc (50)); System.out.println (futur.get ()); } Streaming Call of CompletableFuture: public static entier calc (Integer para) {try {// simule un thread d'exécution long.Sleep (1000); } catch (InterruptedException e) {} return para * para; } public static void Main (String [] args) lève l'interruption, EXECUTUTIONException {complecableFuture <void> fu = terminableFuture .Supplyasync (() -> calc (50)) .thenapply ((i) -> Integer.tostring (i)) .thenapply ((str) -> "/" "+" "") .TheNaCcept (System.out :: println); fu.get (); }Combinez plusieurs transactions complétables:
entier statique public calc (entier para) {return para / 2; } public static void Main (String [] args) lance InterruptedException, ExecutionException {complecableFuture <Void> fu = terminablefuture .SupplyAsync (() -> calc (50)) .Thencompose ((i) -> completsablefuture.supplyasync (() -> calc (i))). "/" ") .TheNaCcept (System.out :: println); fu.get (); } Ces exemples se concentrent davantage sur certaines nouvelles fonctionnalités de Java 8. Voici quelques exemples pour illustrer les fonctionnalités, donc je n'y entrerai pas en profondeur.
Completefuture a peu à voir avec les performances, mais il est plus important de soutenir la programmation fonctionnelle et l'amélioration des fonctions. Bien sûr, la définition du temps d'achèvement est un moment fort.
3. Stampée
Dans l'article précédent, la séparation de verrouillage vient d'être mentionnée et l'implémentation importante de la séparation de verrouillage est ReadWriteLock. Stampedlock est une amélioration de ReadWritelock. La différence entre StampEdLock et ReadWriteLock est que Stampedlock pense que la lecture ne doit pas bloquer les écritures, et Stampedlock pense que lorsque la lecture et l'écriture s'excluent mutuellement, la lecture doit être reliée, plutôt que de ne pas permettre au fil d'écriture d'écrire. Cette conception résout le problème de l'écriture de la faim de fil lors de la lecture plus et de l'écriture moins.
Donc, StampEdLock est une amélioration qui a tendance à écrire des threads.
Exemple Stampedlock:
Importer java.util.concurrent.locks.stampedlock; Public Class Point {Private Double X, Y; Private Final StampedLock Sl = new StampedLock (); VOID MOVE (double deltax, double deltay) {// Une méthode exclusivement verrouillée longue Stamp = Sl.WriteLock (); essayez {x + = deltax; y + = deltay; } enfin {sl.unlockWrite (Stamp); }} double distancefromorigin () {// Une méthode en lecture seule long tampon = Sl.TryOptimistRead (); Double Currentx = x, currenty = y; if (! Sl.Validate (Stamp)) {Stamp = Sl.Readlock (); essayez {currentx = x; currenty = y; } Enfin {Sl.UnlockRead (Stamp); }} return math.sqrt (currentx * currentx + currenty * currenty); }}Le code ci-dessus simule le thread d'écriture et le thread de lecture. StampEdlock vérifie si elle s'exclut mutuellement selon le timbre. Lors de l'écriture d'un timbre une fois, il augmente une certaine valeur.
tryOptimistRead ()
C'est la situation où la lecture et l'écriture ne s'excluent pas mutuellement comme mentionné.
Chaque fois que vous lisez un fil, vous ferez d'abord un jugement
if (! sl.validate (tampon))
Dans Valider, il vérifiera d'abord s'il y a une écriture de threads d'écriture, puis déterminera si la valeur d'entrée est la même que le tampon actuel, c'est-à-dire déterminer si le thread de lecture lira les dernières données.
S'il y a une écriture de discussion d'écriture ou si la valeur du tampon est différente, le retour échoue.
Si le jugement échoue, vous pouvez bien sûr essayer de le lire à plusieurs reprises. Dans l'exemple de code, il n'est pas autorisé à essayer de le lire à plusieurs reprises, mais utilise plutôt le verrou d'optimisme à dégénérer en verrous de lecture ordinaires pour le lire. Cette situation est une méthode de lecture pessimiste.
Stamp = Sl.Readlock ();
Idée de mise en œuvre de Stampedlock:
Clh Spin Lock: Lorsque l'application de verrouillage échoue, le fil de lecture ne sera pas suspendu immédiatement. Une file d'attente en attente sera maintenue dans la serrure. Tous les fils qui s'appliquent aux verrous, mais aucun thread réussi n'est enregistré dans cette file d'attente. Chaque nœud (un nœud représente un thread) enregistre un bit verrouillé pour déterminer si le thread actuel a libéré le verrou. Lorsqu'un fil essaie d'acquérir un verrou, il obtient le nœud de queue de la file d'attente d'attente actuelle comme nœud prédécesseur. Et utiliser des codes comme les suivants pour déterminer si le nœud préampliqué a réussi à publier le verrouillage
while (pré.locked) {
}
Cette boucle doit attendre que le nœud précédent libère le verrou, afin que le thread actuel ne soit pas suspendu par le système d'exploitation, améliorant ainsi les performances.
Bien sûr, il n'y aura pas de tours sans fin, et le fil sera suspendu après plusieurs tours.