Galerie de cartes mentales Carte mentale des connaissances du système de concurrence Java (programmation simultanée)
Il s'agit d'une carte mentale sur la carte des connaissances du système de concurrence Java (programmation simultanée), y compris la file d'attente de blocage, les bases de la concurrence, les verrous, le modèle de mémoire JAVA et d'autres aspects des connaissances.
Modifié à 2023-11-06 19:35:07Cent ans de solitude est le chef-d'œuvre de Gabriel Garcia Marquez. La lecture de ce livre commence par l'analyse des relations entre les personnages, qui se concentre sur la famille Buendía et raconte l'histoire de la prospérité et du déclin de la famille, de ses relations internes et de ses luttes politiques, de son métissage et de sa renaissance au cours d'une centaine d'années.
Cent ans de solitude est le chef-d'œuvre de Gabriel Garcia Marquez. La lecture de ce livre commence par l'analyse des relations entre les personnages, qui se concentre sur la famille Buendía et raconte l'histoire de la prospérité et du déclin de la famille, de ses relations internes et de ses luttes politiques, de son métissage et de sa renaissance au cours d'une centaine d'années.
La gestion de projet est le processus qui consiste à appliquer des connaissances, des compétences, des outils et des méthodologies spécialisés aux activités du projet afin que celui-ci puisse atteindre ou dépasser les exigences et les attentes fixées dans le cadre de ressources limitées. Ce diagramme fournit une vue d'ensemble des 8 composantes du processus de gestion de projet et peut être utilisé comme modèle générique.
Cent ans de solitude est le chef-d'œuvre de Gabriel Garcia Marquez. La lecture de ce livre commence par l'analyse des relations entre les personnages, qui se concentre sur la famille Buendía et raconte l'histoire de la prospérité et du déclin de la famille, de ses relations internes et de ses luttes politiques, de son métissage et de sa renaissance au cours d'une centaine d'années.
Cent ans de solitude est le chef-d'œuvre de Gabriel Garcia Marquez. La lecture de ce livre commence par l'analyse des relations entre les personnages, qui se concentre sur la famille Buendía et raconte l'histoire de la prospérité et du déclin de la famille, de ses relations internes et de ses luttes politiques, de son métissage et de sa renaissance au cours d'une centaine d'années.
La gestion de projet est le processus qui consiste à appliquer des connaissances, des compétences, des outils et des méthodologies spécialisés aux activités du projet afin que celui-ci puisse atteindre ou dépasser les exigences et les attentes fixées dans le cadre de ressources limitées. Ce diagramme fournit une vue d'ensemble des 8 composantes du processus de gestion de projet et peut être utilisé comme modèle générique.
Programmation simultanée
Modèle de mémoire Java (JMM)
Mécanisme de communication par fil de discussion
partage de mémoire
Adoption de Java
Messagerie
modèle de mémoire
Réorganiser
Pour l'exécution du programme, le processeur et le compilateur réorganiseront le programme.
condition
Les résultats de l'exécution du programme ne peuvent pas être modifiés dans un environnement monothread.
La réorganisation n'est pas autorisée s'il existe des dépendances de données
question
La réorganisation peut entraîner des données dangereuses dans un environnement multithread
cohérence séquentielle
Modèle de référence théorique en environnement multithread
Fournit de solides garanties de visibilité de la mémoire pour les programmes
caractéristique
Toutes les opérations dans un thread doivent être effectuées dans l'ordre du programme
Tous les threads ne peuvent voir qu'un seul ordre d'exécution des opérations, que le programme soit synchronisé ou non.
Chaque opération doit être effectuée de manière atomique et immédiatement visible par tous les threads
arrive-avant
La théorie de base de JMM garantit la visibilité de la mémoire
Dans JMM, si les résultats d'une opération doivent être visibles par une autre opération, alors il doit y avoir une relation d'occurrence entre les deux opérations.
théorie
Si une opération se produit avant une autre opération, alors les résultats de l'exécution de la première opération seront visibles pour la deuxième opération, et l'ordre d'exécution de la première opération sera avant la deuxième opération.
L'existence d'une relation d'occurrence avant entre deux opérations ne signifie pas qu'elles doivent être exécutées dans l'ordre spécifié par le principe d'occurrence avant. Si le résultat de l'exécution après la réorganisation est cohérent avec le résultat de l'exécution selon la relation qui se produit avant, alors cette réorganisation n'est pas illégale.
comme si-série
Toutes les opérations peuvent être réorganisées à des fins d'optimisation, mais vous devez vous assurer que les résultats de la réorganisation ne peuvent pas être modifiés.
synchronisé
Synchronisation, verrouillage lourd
principe
synchronisé peut garantir que lorsqu'une méthode ou un bloc de code est en cours d'exécution, une seule méthode peut accéder à la section critique en même temps. Il peut également garantir la visibilité de la mémoire des variables partagées.
verrouiller l'objet
Méthode de synchronisation ordinaire, le verrou est l'objet d'instance actuel
Méthode de synchronisation statique, le verrou est l'objet de classe de la classe actuelle
Bloc de méthode synchronisé, le verrou est l'objet entre parenthèses
Mécanisme de mise en œuvre
En-tête d'objet Java
Le verrou synchronisé est stocké dans l'en-tête de l'objet Java.
Comprend deux parties de données
Marquer le mot (champ de marque)
Mark Word est conçu comme une structure de données non fixe pour stocker un maximum de données dans un très petit espace. Il réutilisera son propre espace de stockage en fonction de l'état de l'objet.
inclure
Code de hachage (HashCode), âge de génération GC, indicateur d'état de verrouillage, verrou détenu par le thread, ID de thread biaisé, horodatage biaisé
Pointeur de classe (type pointeur)
moniteur
Propriétaire
Initialement, NULL signifie qu'aucun thread ne possède actuellement l'enregistrement du moniteur. Lorsque le thread possède avec succès le verrou, l'identifiant unique du thread est enregistré. Lorsque le verrou est libéré, il est défini sur NULL.
Optimisation du verrouillage
verrouillage de la rotation
Le thread attend un certain temps et ne sera pas suspendu immédiatement pour voir si le thread détenant le verrou libérera bientôt le verrou (méthode cyclique)
Le nombre de mots spin est difficile à contrôler (-XX:preBlockSpin)
Théorie existentielle : les threads s'arrêtent et se réveillent fréquemment avec une lourde charge. On peut considérer que chaque thread détient le verrou pendant une courte période et que le gain dépasse le gain après la suspension puis le réveil du thread.
défaut
Le nombre de tours ne peut pas être déterminé
verrouillage de rotation adaptatif
Le nombre de tours n'est plus fixe. Il est déterminé par le temps de tour précédent sur la même écluse et le statut du propriétaire de la serrure.
Si le tour réussit, le nombre de tours peut être augmenté. Si l'acquisition du verrou échoue fréquemment, le nombre de tours sera réduit.
élimination du verrou
S'il n'y a pas de concurrence sur les données, la JVM éliminera le mécanisme de verrouillage
Jugements fondés
Échappement variable
dégrossissage des serrures
Connectez plusieurs opérations de verrouillage et de déverrouillage consécutives pour créer un verrou plus grand. Par exemple, acquérir un verrou dans une boucle for
serrure légère
Réduisez la consommation de performances causée par les verrous lourds traditionnels à l’aide de mutex du système d’exploitation sans concurrence multithread.
Acquérir et libérer des verrous via CAS
base de performance
Pour la plupart des serrures, il n’y aura pas de concurrence pendant tout le cycle de vie.
défaut
Dans un environnement multithread, son efficacité de fonctionnement est plus lente que celle des verrous lourds.
verrouillage de biais
Afin de minimiser les chemins d'exécution de verrous légers inutiles sans concurrence multithread
Évitez autant que possible les opérations CAS inutiles. Si le verrou de compétition échoue, passez à un verrou léger.
volatil
caractéristique
Visibilité volatile : lors de la lecture d'un volatile, vous pouvez toujours voir l'écriture finale dans cette variable.
Atomicité volatile : volatile est atomique pour une seule lecture/écriture (32 bits Long, Double), à l'exception des opérations composées, telles que i ;
Mécanisme de mise en œuvre
barrière de mémoire
sémantique de la mémoire
Lors de l'écriture d'une variable volatile, JMM actualisera immédiatement la valeur de la variable partagée dans la mémoire locale correspondant au thread vers la mémoire principale.
Lors de la lecture d'une variable volatile, JMM définira la mémoire locale correspondant au thread comme invalide et lira la variable partagée directement depuis la mémoire principale.
sémantique du système d'exploitation
Mémoire principale, cache (thread privé) cohérent ?
solution
En ajoutant LOCK# au bus
Via le protocole de cohérence du cache (protocole MESI)
modèle de mémoire
Réorganiser
arrive-avant
DCL
Modèle singleton
DCL
Réorganiser
arrive-avant
solution
solution volatile
Désactiver la réorganisation
Solution basée sur l'initialisation de classe
Utilisez le mécanisme classloder pour vous assurer qu’il n’y a qu’un seul thread lors de l’initialisation de l’instance. La JVM va acquérir un verrou lors de la phase d'initialisation de la classe. Ce verrou peut synchroniser l'initialisation de la même classe par plusieurs threads.
Bases de la concurrence
AQS
AbstractQueuedSynchronizer, synchroniseur, implémente les composants de base de JUC
Résolution d'un grand nombre de problèmes détaillés liés à l'implémentation des synchroniseurs dans les sous-classes, tels que l'obtention de l'état de synchronisation et de la file d'attente de synchronisation FIFO.
À l'aide du modèle de méthode modèle, AQS implémente un grand nombre de méthodes courantes et les sous-classes implémentent leurs méthodes abstraites via l'héritage pour gérer l'état de synchronisation.
File d'attente de synchronisation CLH
File d'attente bidirectionnelle FIFO, AQS s'appuie sur elle pour résoudre le problème de gestion de l'état de synchronisation
Le premier nœud se réveille et attend que la file d'attente soit ajoutée à la fin de la file d'attente de synchronisation CLH.
Acquisition et libération d'état synchrones
Exclusif
Obtenir le verrouillage
Obtenir l'état de synchronisation : acquérir
AcquérirInterruptible : acquérirInterruptiblement
Acquisition du délai d'attente : tryAcquireNanos
déverrouiller le verrou
libérer
partagé
Obtenir le verrouillage
acquérirPartagé
déverrouiller le verrou
releasePartagé
Blocage des fils et réveil
Lorsqu'un thread acquiert le verrou, les autres threads doivent se bloquer lors de l'acquisition à nouveau. Lorsque le thread libère le verrou, AQS est responsable du réveil du thread.
Support de verrouillage
Est-ce que la primitive de base de blocage de thread est utilisée pour créer des verrous et d'autres classes de synchronisation
Chaque thread utilisant LockSupport est associé à une autorisation si l'autorisation est disponible et peut être utilisée dans le processus, l'appel de park() sera immédiatement renvoyé, sinon il risque de se bloquer. Si la licence n'est pas encore disponible, vous pouvez appeler unpark pour la rendre disponible
garer(), déparquer()
CAS
Compare And Swap, la théorie centrale et la plus fondamentale de l'ensemble du système JUC
Valeur mémoire V, ancienne valeur attendue A et valeur à mettre à jour B. Si et seulement si la valeur de la valeur mémoire V est égale à l'ancienne valeur attendue A, la valeur de la valeur mémoire V sera modifiée en B, sinon rien ne sera modifié. être terminé.
Il y a quatre paramètres en natif
défaut
Temps de cycle trop long
Une seule variable partagée peut être garantie comme étant exploitée de manière atomique
problème ABA
solution
numéro de version
AtomicStampedRéférence
Verrouillage
Verrouillage réentrant
Le verrouillage réentrant est un mécanisme de synchronisation récursif non bloquant
Un mécanisme de verrouillage plus puissant et plus flexible que le mécanisme synchronisé, qui peut réduire la probabilité de blocage.
Divisé en verrouillage équitable et verrouillage injuste
La couche inférieure est implémentée à l'aide d'AQS et hérite d'AQS via la synchronisation interne.
RéentrantReadWriteLock
Verrou en lecture-écriture, deux verrous : verrou partagé : verrou en lecture, verrou exclusif : verrou en écriture
Prend en charge l'équité, l'injustice, la réentrée et la dégradation des verrous
Rétrogradation du verrouillage : selon l'ordre d'acquisition du verrouillage en écriture, d'acquisition du verrouillage en lecture et de libération du verrouillage en écriture, le verrouillage en écriture peut être rétrogradé en verrouillage en lecture.
Condition
Lock fournit une Condition, qui est plus détaillée et flexible pour les opérations d'attente et de réveil des threads.
Une file d’attente de conditions est gérée en interne. Lorsque le thread actuel appelle la méthode wait(), un nœud (Node) sera construit à partir du thread actuel et le nœud sera ajouté à la fin de la file d'attente.
Outils de concurrence
Barrière cyclique
Il permet à un groupe de threads de s'attendre jusqu'à ce qu'un point de barrière commun soit atteint
En termes simples : laissez un groupe de threads être bloqué lorsqu'ils atteignent une barrière. La barrière ne s'ouvrira pas tant que le dernier thread n'atteindra pas la barrière, et tous les threads interceptés par la barrière continueront à fonctionner.
La couche inférieure est implémentée à l'aide de la condition ReentrantLock
Scénarios d'application
L'opération de fusion des résultats multi-threads est utilisée pour calculer les données dans plusieurs threads et enfin fusionner les résultats du calcul.
Compte à rebours
Il permet à un ou plusieurs threads d'attendre qu'un ensemble d'opérations effectuées dans d'autres threads soit terminé.
Initialise CountDownLatch avec le nombre donné. Étant donné que la méthode countDown() est appelée, la méthode wait se bloque jusqu'à ce que le décompte actuel atteigne zéro. Ensuite, tous les threads en attente sont libérés et tous les appels suivants à wait reviennent immédiatement. Ce comportement ne se produit qu'une seule fois : le décompte ne peut pas être réinitialisé. Si vous devez réinitialiser le décompte, envisagez d'utiliser un CyclicBarrier.
Différence avec CyclicBarrier
La fonction de CountDownLatch est de permettre à 1 ou N threads d'attendre que d'autres threads terminent leur exécution tandis que CyclicBarrier permet à N threads de s'attendre les uns les autres.
Le compteur de CountDownLatch ne peut pas être réinitialisé ; le compteur de CyclicBarrier peut être réinitialisé et utilisé, c'est pourquoi on l'appelle une barrière cyclique.
Implémenté en interne à l'aide de verrous partagés
Sémaphore
signal
Un compteur qui contrôle l'accès à plusieurs ressources partagées
Conceptuellement, un sémaphore gère un ensemble d'autorisations. Si nécessaire, chaque acquire() bloque jusqu'à ce que l'autorisation soit disponible, puis acquiert l'autorisation. Chaque release() ajoute une autorisation, libérant potentiellement un getter bloquant. Cependant, au lieu d'utiliser l'objet de licence réel, Semaphore compte simplement le nombre de licences disponibles et prend les mesures en conséquence.
Le sémaphore Le sémaphore est un entier non négatif (>=1). Lorsqu'un thread souhaite accéder à une ressource partagée, il doit d'abord obtenir le sémaphore. Lorsque le sémaphore > 0, obtenez la ressource et définissez le sémaphore - 1. Si la valeur du Sémaphore = 0, cela signifie que toutes les ressources partagées ont été occupées par d'autres threads et que le thread doit attendre que d'autres threads libèrent les ressources. Lorsque le thread libère la ressource, le Sémaphore est 1
Scénarios d'application
Souvent utilisé pour limiter le nombre de threads pouvant accéder à certaines ressources (physiques ou logiques)
Implémenté en interne à l'aide de verrous partagés
Échangeur
Un point de synchronisation pour les threads qui peuvent associer et échanger des éléments dans une paire
Permet l'échange de données entre tâches simultanées. Plus précisément, la classe Exchanger permet de définir des points de synchronisation entre deux threads. Lorsque les deux threads atteignent le point de synchronisation, ils échangent des structures de données, de sorte que la structure de données du premier thread va dans le deuxième thread, et la structure de données du deuxième thread va dans le premier thread.
autre
SujetLocal
Une solution au problème des variables membres dans un environnement multithread, mais n'a rien à voir avec la synchronisation des threads. L'idée est de créer une copie distincte de la variable pour chaque thread, afin que chaque thread puisse modifier indépendamment sa propre copie de la variable sans affecter les copies correspondantes des autres threads.
ThreadLocal n'est pas utilisé pour résoudre le problème des variables partagées, ni pour coordonner la synchronisation des threads, mais est un mécanisme introduit pour permettre à chaque thread de gérer son propre état.
quatre méthodes
get() : renvoie la valeur dans la copie du thread actuel de cette variable locale du thread
initialValue() : renvoie la "valeur initiale" du thread actuel pour cette variable locale de thread
Remove() : Supprime la valeur de cette variable locale de thread dans le thread actuel
set (valeur T) : définit la valeur dans la copie du thread actuel de cette variable locale du thread sur la valeur spécifiée
ThreadLocalMap
La clé pour implémenter le mécanisme d'isolation des threads
Chaque thread possède une variable membre de type ThreadLocal.ThreadLocalMap à l'intérieur, qui est utilisée pour stocker une copie de la variable ThreadLocal réelle.
Fournit une méthode pour stocker une copie des variables de chaque thread à l’aide de paires clé-valeur. La clé est l’objet ThreadLocal actuel et la valeur est la copie variable du thread correspondant.
sois prudent
L'instance ThreadLocal elle-même ne stocke pas de valeur, elle fournit simplement une clé pour trouver une copie de la valeur dans le thread actuel.
Il s'agit de ThreadLocal contenu dans Thread, et non de Thread contenu dans ThreadLocal.
problème de fuite de mémoire
ThreadLocalMap
la clé est une valeur de référence faible est une référence forte et ne peut pas être recyclée
Appeler explicitement Remove()
Fourcher/Rejoindre
Un framework pour exécuter des tâches en parallèle est un framework qui divise les grandes tâches en plusieurs petites tâches, et résume enfin les résultats de chaque petite tâche pour obtenir les résultats de la grande tâche.
idée principale
"Cloison"
fork décompose les tâches et join collecte les données
vol d'emploi
Un thread vole des tâches dans d'autres files d'attente pour les exécuter
Le thread qui exécute le bloc aide le thread lent à exécuter la tâche et améliore l'efficacité de l'ensemble de la tâche.
La file d'attente doit utiliser une file d'attente bidirectionnelle
classe de base
ForkJoinPool
Pool de threads pour exécuter des tâches
ForkJoinTask
Représente les tâches, abstraction des tâches pour ForkJoinPool
ForkJoinWorkerThread
Thread de travail qui effectue des tâches
Collections simultanées Java
ConcurrentHashMap
CAS Synchronized garantit la sécurité des mises à jour simultanées. La couche inférieure utilise une structure de stockage de liste chaînée/arborescence rouge-noir.
Classes internes importantes
Nœud
paire clé-valeur clé-valeur
Nœud d'arbre
Noeud d'arbre rouge-noir
ArbreBin
C'est l'équivalent d'un arbre rouge-noir. Sa méthode de construction est en fait le processus de construction d'un arbre rouge-noir.
Nœud de transfert
Nœud auxiliaire, utilisé pour l'opération d'expansion ConcurrentHashMap
tailleCtl
Identifiant de contrôle, utilisé pour contrôler les opérations d'initialisation et d'expansion de la table
signification
Un nombre négatif indique que des opérations d'initialisation ou d'extension sont en cours.
-1 signifie initialisation
-N indique qu'il y a N-1 threads en cours d'opérations d'expansion
Un nombre positif ou 0 indique que la table de hachage n'a pas été initialisée. Cette valeur indique la taille de l'initialisation ou de la prochaine expansion.
Opérations importantes
table d'initialisation
Méthode d'initialisation ConcurrentHashMap
Un seul thread peut participer au processus d'initialisation, les autres threads doivent être suspendus
Le constructeur n'effectue pas le processus d'initialisation. L'initialisation est en fait déclenchée par l'opération put.
étape
sizeCtl < 0 signifie que l'initialisation est en cours et que le thread est suspendu
Le thread obtient la qualification d'initialisation (CAS(SIZECTL, sc, -1)) pour effectuer le processus d'initialisation
Une fois l'étape d'initialisation terminée, définissez sizeCtl = 0,75 * n (le prochain seuil d'expansion), indiquant la taille de la prochaine expansion
mettre
idée principale
Calculez la position du nœud inséré dans le tableau en fonction de la valeur de hachage. Si la position est vide, insérez-le directement, sinon insérez-le dans une liste chaînée ou une arborescence.
La situation réelle est plus compliquée
étape
La table est nulle et le thread entre dans l'étape d'initialisation. Si d'autres threads s'initialisent, le thread se bloque.
Si la position i actuelle insérée est nulle, cela signifie que cette position est insérée pour la première fois. Utilisez simplement CAS pour insérer le nœud. Si l'insertion réussit, addCount est appelé pour déterminer si une expansion est nécessaire. Si l'insertion échoue, continuez la correspondance (tourner)
Si le hachage du nœud == MOVED (-1), cela signifie qu'un thread est en expansion, et il entrera dans le processus d'expansion.
Dans d'autres cas, les nœuds sont insérés selon la liste chaînée ou l'arborescence rouge-noir, mais ce processus nécessite un verrouillage (synchronisé)
obtenir
étape
table==null;retourner null
Obtenir à partir d'une liste chaînée/nœud d'arbre rouge-noir
Expansion
Extension multithread
étape
Créez un nextTable dont la taille est deux fois la taille d'origine. Cette étape est réalisée dans un environnement monothread.
Copiez le contenu de la table d'origine dans nextTable. Cette étape permet des opérations multithread.
Le processus de conversion d'une liste chaînée en un arbre rouge-noir
Le nombre d'éléments dans la liste chaînée atteint le seuil 8, puis la liste chaînée est convertie en arbre rouge-noir
Algorithme d'arbre rouge-noir
La différence entre 1,8 et 1,7
ConcurrentLinkedQueue
Une file d'attente thread-safe illimitée basée sur des nœuds de liaison, utilisant le principe FIFO pour trier les éléments et implémentée en interne à l'aide de l'algorithme CAS
immutabilité
Le prochain du dernier élément de la file d'attente est nul
Les éléments de tous les nœuds non supprimés de la file d'attente ne peuvent pas être nuls et peuvent être parcourus à partir du nœud principal.
Pour que le nœud soit supprimé, au lieu de le définir directement sur null, définissez d'abord son champ d'élément sur null (l'itérateur ignorera les nœuds avec un élément nul)
Autorisez le décalage des mises à jour de tête et de queue. Qu'est-ce que ça veut dire? Cela signifie que head et tail ne pointent pas toujours vers le premier élément et le dernier élément (expliqué plus tard)
Invariance et variabilité de la tête
Invariance et variabilité de la queue
Subtilité : CAS est utilisé pour effectuer des opérations sur les données tout en autorisant des incohérences dans la file d'attente, et une faible cohérence est pleinement démontrée.
ConcurrentSkipListMap
La troisième structure de données clé-valeur : SkipList (skip list)
Sauter la liste
Structure arborescente binaire équilibrée
La liste de saut permet aux données triées d'être distribuées dans une liste chaînée multicouche, en utilisant un nombre aléatoire de 0 à 1 pour déterminer si une donnée montera ou non, en utilisant un algorithme « d'échange d'espace contre du temps ». Un pointeur vers l'avant est ajouté à chaque nœud, et certains nœuds impossibles à impliquer peuvent être ignorés lors de l'insertion, de la suppression et de la recherche, améliorant ainsi l'efficacité.
caractéristique
Il est composé de nombreuses couches de structure et les niveaux sont générés aléatoirement selon une certaine probabilité.
Chaque niveau est une liste chaînée ordonnée. La valeur par défaut est l'ordre croissant. Elle peut également être triée selon le comparateur fourni lors de la création du mappage, en fonction du constructeur utilisé.
La liste chaînée de niveau le plus bas (niveau 1) contient tous les éléments
Si un élément apparaît dans la liste chaînée du niveau i, alors il apparaîtra également dans les listes chaînées sous le niveau i.
Chaque nœud contient deux pointeurs, l'un pointant vers l'élément suivant dans la même liste chaînée et l'autre pointant vers l'élément situé un niveau en dessous.
Rechercher, supprimer, ajouter
ConcurrentSkipListSet
Implémenté en interne à l'aide de ConcurrentSkipListMap
atomique
classe de types de base
Utilisé pour mettre à jour les types de base de manière atomique
AtomiqueBooléen
Type booléen de mise à jour atomique
Entier atomique
Entier de mise à jour atomique
AtomiqueLong
Mise à jour atomique longue
tableau
Mettre à jour un élément dans un tableau de manière atomique
Tableau d'entiers atomiques
Mise à jour atomique des éléments dans un tableau d'entiers
TableauLongAtomique
Mise à jour atomique des éléments dans un tableau d'entiers longs
Tableau de référence atomique
Mise à jour atomique des éléments dans un tableau de type référence
Type de référence
Si vous souhaitez mettre à jour plusieurs variables de manière atomique, vous devez utiliser la classe fournie par ce type de référence de mise à jour atomique.
Référence atomique
Mise à jour atomique des types de référence
AtomicReferenceFieldUpdater
Mise à jour atomique des champs dans les types référence
AtomicMarkableRéférence
Mise à jour atomique des types de référence avec des bits d'indicateur
Classe de terrain
Si nous n'avons besoin que d'un certain champ dans une certaine classe, nous devons alors utiliser la mise à jour atomique de la classe de champ
AtomicIntegerFieldUpdater
Programme de mise à jour pour la mise à jour atomique des champs entiers
AtomicLongFieldUpdater
Programme de mise à jour pour la mise à jour atomique des champs longs
AtomicStampedRéférence
Mise à jour atomique du type de référence avec numéro de version
file d'attente bloquante
ArrayBlockingQueue
Une file d'attente de blocage limitée FIFO implémentée sous forme de tableau
ArrayBlockingQueue est limité et fixe. La taille est confirmée lors du constructeur. Les modifications ne sont pas prises en charge après confirmation.
"L'équité" n'est pas garantie dans un environnement multithread
accomplir
Verrouillage réentrant
Condition
LinkedBlockingQueue
File d'attente de blocage FIFO illimitée, basée sur des liens
File d'attente de blocage prioritaire
File d'attente de blocage illimitée avec prise en charge prioritaire
Par défaut, les éléments sont triés par ordre croissant dans l'ordre naturel. Vous pouvez trier les éléments en spécifiant un comparateur.
tas binaire
Classification
tas maximum
La valeur clé du nœud parent est toujours supérieure ou égale à la valeur clé de tout nœud enfant
tas minimum
La valeur clé du nœud parent est toujours inférieure ou égale à la valeur clé de tout nœud enfant
L'opération d'ajout "monte" constamment, tandis que l'opération de suppression "tombe" constamment.
accomplir
Condition de verrouillage réentrant
tas binaire
Retarder la file d'attente
File d'attente de blocage illimitée prenant en charge l'acquisition retardée d'éléments
application
Cache : effacez les données mises en cache qui ont expiré dans le cache
Traitement du délai d'expiration des tâches
accomplir
Condition de verrouillage réentrant
File d'attente prioritaire triée en fonction du temps de retard : PriorityQueue
Interface retardée
Utilisé pour marquer les objets qui doivent être exécutés après un délai donné
Cette interface nécessite que les classes qui l'implémentent doivent définir une méthode compareTo qui fournit un classement cohérent avec la méthode getDelay de cette interface.
File d'attente synchrone
Une file d'attente bloquante sans capacité
application
Pour échanger du travail, le fil du producteur et le fil du consommateur sont synchronisés pour délivrer certaines informations, événements ou tâches
Difficile à comprendre, a des difficultés avec Exchanger
LinkedTransferQueue
File d'attente de blocage illimitée composée d'une liste chaînée
Équivalent à un surensemble de ConcurrentLinkedQueue, SynchronousQueue (en mode équitable), LinkedBlockingQueues illimitées, etc.
mode préemptif
S'il est disponible, prenez-le directement. Sinon, il occupera cette position jusqu'à ce qu'il soit obtenu ou expire ou soit interrompu.
LinkedBlockingDeque
Une file d'attente de blocage bidirectionnelle composée d'une liste chaînée
La capacité est facultative. Vous pouvez définir la capacité lors de l'initialisation pour éviter une expansion excessive. Si elle n'est pas définie, la capacité par défaut est Integer.MAX_VALUE.
utiliser
Modèle de « vol d'emploi »
Pool de threads
avantage
Réduire la consommation de ressources
Réduisez le coût de création et de destruction des threads en réutilisant les threads créés
Améliorer la vitesse de réponse
Lorsqu'une tâche arrive, elle peut être exécutée immédiatement sans attendre la création du thread.
Améliorer la gestion des threads
Allocation, réglage et surveillance unifiés
Exécuteur
Exécuteurs testamentaires
La classe d'usine statique fournit des méthodes d'usine statiques d'Executor, ExecutorService, ScheduledExecutorService, ThreadFactory, Callable et d'autres classes.
ThreadPoolExécuteur
Signification du paramètre
taille du pool de base
Le nombre de threads principaux dans le pool de threads
taille maximale de la piscine
Le nombre maximum de threads autorisés dans le pool de threads
garderAliveTime
Temps d'inactivité du fil de discussion
unité
unité de keepAliveTime
file d'attente de travail
Une file d'attente de blocage utilisée pour contenir les tâches en attente d'exécution
file d'attente de blocage utilisée
ArrayBlockingQueue
LinkedBlockingQueue
File d'attente synchrone
File d'attente de blocage prioritaire
filFactory
Usine utilisée pour configurer la création de threads
DefaultThreadFactory
gestionnaire
RejectedExecutionHandler, stratégie de rejet du pool de threads
Classification
AbortPolicy : lancer une exception directement, politique par défaut
CallerRunsPolicy : utilisez le thread où se trouve l'appelant pour exécuter des tâches
DiscardOldestPolicy : supprime la tâche la plus en avant dans la file d'attente de blocage et exécute la tâche en cours
DiscardPolicy : abandonner la tâche directement
Classification du pool de threads
nouveauFixedThreadPool
Pool de threads réutilisable avec un nombre fixe de threads
analyser
corePoolSize est cohérent avec maximumPoolSize
Utiliser une file d'attente "illimitée" LinkedBlockingQueue
maximumPoolSize, keepAliveTime, Gestionnaire d'exécution rejeté invalide
nouveauCachedThreadPool
Exécuteur utilisant un seul thread de travail
analyser
corePoolSize et maximumPoolSize sont définis sur 1
Utiliser LinkedBlockingQueue comme workerQueue
nouveauSingleThreadExecutor
Un pool de threads qui crée de nouveaux threads selon les besoins
analyser
corePoolSize est défini sur 0
maximumPoolSize est défini sur Integer.MAX_VALUE
SynchronousQueue en tant que WorkerQueue
Si le thread principal soumet des tâches plus rapidement que les threads des tâches de processus maximumPool, CachedThreadPool continuera à créer de nouveaux threads, ce qui peut épuiser les ressources CPU et mémoire.
Soumission des tâches
Exécuteur.execute()
ExecutorService.submit()
Exécution des tâches
Processus de mise en œuvre
Réglage du pool de threads
Deux modèles
Surveillance du pool de threads
ScheduledThreadPoolExecutor
Hérité de ThreadPoolExecutor
Exécutez la tâche après un délai donné ou exécutez la tâche périodiquement
DelayQueue est utilisé en interne pour l'implémenter, et les tâches planifiées sont placées dans DelayQueue. DelayQueue encapsule en interne PriorityQueue, qui trie les ScheduledFutureTasks dans la file d'attente.
Avenir
Calcul asynchrone
Avenir
Assurer les opérations
Annulation des tâches d'exécution
Demander si la tâche est terminée
Obtenez les résultats de l'exécution des tâches
Tâche future
Implémentez l'interface RunnableFuture, qui peut être exécutée en tant que Runnable ou utilisée comme Future pour obtenir la valeur de retour de Callable
Implémenté en interne sur la base d'AQS