Les dernières questions d'entretien pour le recrutement automne 2020: Questions d'entretien haute fréquence de programmation simultanée: verrouillage réentrant + pool de threads + modèle de mémoire, etc. (y compris les réponses)

Pour un programmeur Java, être capable de maîtriser la programmation concurrente est l'un des critères importants pour juger de son excellence. Parce que la programmation concurrente est le point de connaissance le plus obscur du langage Java, elle implique les capacités de base du système d'exploitation, de la mémoire, du processeur, du langage de programmation, etc., et elle teste les compétences internes d'un programmeur.
Alors, comment apprendre la programmation simultanée? Il existe de nombreuses boîtes à outils simultanées dans le SDK Java. Devez-vous mémoriser les avantages et les inconvénients et les scénarios d'utilisation de chaque outil? Bien sûr que non. Si vous voulez apprendre la programmation simultanée, vous devez apprendre d'un seul «Sauté» des connaissances et de la technologie de la Chine, a examiné le problème d'un point de vue de haut niveau et a progressivement établi son propre système de connaissances.

ReentrantLock et autres problèmes liés aux verrous explicites

Question 1: Par rapport à Synchronized, quelle est la différence dans le principe de mise en œuvre de Reentrant Lock?

En fait, le principe de réalisation de la serrure est fondamentalement d'atteindre un objectif: faire voir à tous les threads une certaine marque. Synchronized atteint cet objectif en définissant une marque dans l'en-tête de l'objet. Il s'agit d'une méthode d'implémentation native de verrouillage JVM. Le verrouillage réentrant et toutes les classes d'implémentation basées sur l'interface Lock sont tous implémentés à l'aide d'une variable int modifiée volitile, et Pour garantir que chaque thread puisse avoir une visibilité et une modification atomique de l'int, son essence est basée sur le framework AQS.

Question 2: Parlez donc du cadre AQS?

AQS (Abstract Queued Synchronizer class) est un cadre pour la construction de verrous et de synchroniseurs, les verrous dans divers packages de verrouillage (couramment utilisés sont Reentrant Lock, ReadWrite Lock), et d'autres tels que Semaphore, Count Down Latch et même les premiers Future Task, etc. sont tous basés sur AQS à construire.

1. AQS définit une variable d'état int volatile en interne, qui représente l'état de synchronisation: lorsque le thread appelle la méthode de verrouillage, si état = 0, cela signifie qu'aucun thread ne détient le verrou de la ressource partagée, et le verrou peut être obtenu et état = 1; si état = 1, cela signifie qu'un thread utilise actuellement la variable partagée et que les autres threads doivent rejoindre la file d'attente de synchronisation pour attendre.

2. AQS termine le travail de mise en file d'attente des threads acquérant des verrous via une file d'attente synchronisée avec une structure de liste doublement liée formée par les classes internes de Node. Lorsqu'un thread ne parvient pas à acquérir le verrou, il est ajouté à la fin de la file d'attente.

  • La classe Node est une encapsulation du thread qui veut accéder au code de synchronisation. Elle contient le thread lui-même et son statut appelé wait Status (il existe cinq valeurs différentes, qui indiquent si elles sont bloquées, si elles sont en attente de réveil, si elles ont été annulées, etc.). Le nœud Node associe son nœud précédent et le nœud suivant pour permettre au thread de réveiller rapidement le prochain thread en attente après avoir libéré le verrou. Il s'agit d'un processus FIFO.
  • La classe Node a deux constantes, SHARED et EXCLUSIVE, qui représentent respectivement le mode partagé et le mode exclusif. Le mode dit partagé est un verrou qui permet à plusieurs threads de fonctionner en même temps (le sémaphore Semaphore est basé sur le mode partagé d'AQS), et le mode exclusif est qu'un seul thread peut fonctionner sur des ressources partagées dans le même laps de temps, et les threads de demande redondants doivent être mis en file d'attente Attendez (comme Reentran Lock).

3. AQS

Construisez une file d'attente (il peut y en avoir plusieurs) via l'objet Condition Object de la classe interne. Lorsque Condition appelle la méthode wait (), le thread rejoindra la file d'attente et lorsque Condition appelle la méthode signal (), le thread passera de la file d'attente à la synchronisation mobile. Verrouillez la concurrence dans la file d'attente.

4. AQS

Chaque et Condition gèrent des files d'attente différentes. Lorsque Lock et Condition sont utilisés, ils se déplacent en fait entre les deux files d'attente.

Question 3: Veuillez comparer les similitudes et les différences entre le verrouillage synchronisé et réentrant autant que possible.

Reentrant Lock est la classe d'implémentation de Lock, qui est un verrou de synchronisation mutuellement exclusif.

D'un point de vue fonctionnel, Reentrant Lock est plus raffiné que l'opération de synchronisation de Synchronized (car il peut être utilisé comme un objet normal), et implémente même des fonctions avancées que Synchronized n'a pas, telles que:

  • L'attente peut être interrompue: lorsque le thread qui maintient le verrou ne libère pas le verrou pendant une longue période, le thread en attente peut choisir d'abandonner l'attente, ce qui est utile pour traiter des blocs synchronisés avec un temps d'exécution très long.
  • Tentative d'acquérir le verrou avec expiration du délai: acquérez le verrou dans la plage de temps spécifiée et revenez si le temps est écoulé et ne peut toujours pas être acquis.
  • Vous pouvez déterminer si des threads attendent dans la file d'attente pour acquérir le verrou.
  • Peut répondre aux demandes d'interruption: contrairement à Synchronized, lorsque le thread qui a acquis le verrou est interrompu, il peut répondre à l'interruption, l'exception d'interruption sera levée et le verrou sera libéré.
  • Un verrouillage équitable peut être obtenu.

Du point de vue de la libération du verrou, Synchronized est implémenté au niveau de la JVM. Non seulement le verrou synchronisé peut être surveillé via certains outils de surveillance, mais également lorsque l'exécution du code est anormale, la JVM libère automatiquement le verrou; mais l'utilisation de Lock ne fonctionne pas. Le verrouillage est implémenté via le code Pour vous assurer que le verrou sera libéré, vous devez mettre un Lock () in finally {}.

Du point de vue des performances, l'implémentation précoce de Synchronized était relativement inefficace. Par rapport à Reentrant Lock, les performances de la plupart des scénarios sont assez différentes. Mais il a été beaucoup amélioré dans Java 6, quand la concurrence n'est pas féroce,

Les performances de Synchronized sont meilleures que celles de Reetrant Lock; sous une forte concurrence, les performances de Synchronized chuteront des dizaines de fois, mais les performances de Reetrant Lock peuvent rester normales.

Question 4: Comment Reentrant Lock réalise-t-il la réentrance?

Reentrant Lock personnalise en interne le synchroniseur Sync (Sync implémente à la fois AQS et AOS, et AOS fournit un moyen de maintenir un verrou mutex.) En fait, il utilise l'algorithme CAS pour placer l'objet thread lorsque le verrou est verrouillé. Dans une liste doublement liée, à chaque fois qu'un verrou est acquis, vérifiez si l'ID de thread actuellement maintenu est le même que l'ID de thread actuellement demandé, et le même peut être saisi à nouveau.

Question 5: En plus de Reetrant Lock, à quels outils de concurrence avez-vous été exposé dans JUC?

Question 6: Veuillez parler de Read Write Lock et Stamped Lock.

Question 7: Comment synchroniser les threads Java les uns avec les autres? Quels synchroniseurs connaissez-vous? Veuillez les présenter séparément.

Question 8: La barrière cyclique et le verrou de décompte se ressemblent beaucoup, veuillez comparer?

Problèmes liés au pool de threads Java

Question 1: Comment le pool de threads est-il implémenté en Java?

 En Java, le soi-disant «thread» dans le pool de threads est en fait abstrait en tant que classe interne statique Worker, qui est implémenté sur la base d'AQS et stocké dans la variable membre de travail Hash Set <Worker> du pool de threads;

 Les tâches à exécuter sont stockées dans la file d'attente de travail de la variable membre (Blocking Queue <Runnable> work Queue). De cette manière, l'idée de base de la réalisation de l'ensemble du pool de threads est la suivante: retirer en permanence les tâches qui doivent être exécutées de la file d'attente de travail et les placer dans les Workers pour traitement.

Question 2: Combien de paramètres de construction de base sont nécessaires pour créer un pool de threads?

La création de pools de threads en Java est en fait très flexible. Nous pouvons créer des pools de threads avec différents comportements en configurant différents paramètres. Ces paramètres incluent: core Pool Size: le nombre de threads core dans le thread pool.

  • Taille maximale du pool: nombre maximal de threads autorisés dans le pool de threads.
  • Keep Alive Time: temps de survie des threads inactifs lorsque le nombre de threads principaux est dépassé.
  • File d'attente de travail: file d'attente qui enregistre la tâche avant que la tâche ne soit exécutée et enregistre la tâche exécutable soumise par la méthode d'exécution.

Question 3: Comment les threads du pool de threads sont-ils créés? A-t-il été créé au début avec le début du pool de threads?

Évidemment pas. Une fois le pool de threads initialisé par défaut, le Worker n'est pas démarré et il est démarré uniquement en cas de demande. Chaque fois que nous appelons la méthode execute () pour ajouter une tâche, le pool de threads fera les jugements suivants:

 Si le nombre de threads en cours d'exécution est inférieur à la taille du pool de base, créez immédiatement un thread pour exécuter cette tâche;

 Si le nombre de threads en cours d'exécution est supérieur ou égal à la taille du pool de base, placez la tâche dans la file d'attente;

 Si la file d'attente est pleine à ce moment et que le nombre de threads en cours d'exécution est inférieur à la taille maximale du pool, créez un thread non principal pour exécuter la tâche immédiatement;

 Si la file d'attente est pleine et que le nombre de threads en cours d'exécution est supérieur ou égal à la taille maximale du pool, le pool de threads lèvera une exception Rejeter l'exception d'exécution. Lorsqu'un thread termine sa tâche, il supprime la tâche suivante de la file d'attente pour exécution. Lorsqu'un thread n'a rien à faire pendant un certain temps (Keep Alive Time), le pool de threads sera déconnecté.

Si le nombre de threads en cours d'exécution est supérieur à la taille du pool de base, ce thread est arrêté. Ainsi, une fois toutes les tâches du pool de threads terminées, il finira par se réduire à la taille de la taille du pool de base.

Question 4: Puisqu'il est mentionné que différents pools de threads peuvent être créés en configurant différents paramètres, quels pools de threads sont implémentés par défaut en Java? Veuillez comparer leurs similitudes et leurs différences.

Question 5: Comment soumettre des threads dans le pool de threads Java?

…………………………

Problèmes liés au modèle de mémoire Java

Question 1: Quel est le modèle de mémoire de Java et comment les threads en Java voient-ils les variables de chacun?

Le modèle de mémoire de Java définit les règles d'accès de chaque variable du programme, c'est-à-dire les détails de bas niveau tels que le stockage des variables dans la machine virtuelle et leur suppression de la mémoire.

Les variables ici incluent les champs d'instance, les champs statiques et les éléments qui composent l'objet tableau, mais n'incluent pas les variables locales et les paramètres de méthode. Comme ils sont privés de threads et ne seront pas partagés, il n'y a pas de problème de concurrence.

Comment les threads en Java voient-ils les variables les uns des autres? Les concepts de mémoire principale et de mémoire de travail sont définis en Java:

Toutes les variables sont stockées dans la mémoire principale, et chaque thread a sa propre mémoire de travail, qui stocke une copie de la copie de la mémoire principale des variables utilisées par le thread. Toutes les opérations (lecture, affectation) des variables par threads doivent être effectuées en mémoire de travail, et les variables de la mémoire principale ne peuvent pas être directement lues et écrites. Différents threads ne peuvent pas accéder directement aux variables de la mémoire de travail de l'autre, et le transfert de valeurs de variables entre threads doit passer par la mémoire principale.

Question 2: Veuillez parler des caractéristiques de volatile et pourquoi il peut garantir la visibilité des variables à tous les threads?

Question 3: Puisque volatile peut garantir la visibilité des variables entre les threads, cela signifie-t-il que les opérations basées sur des variables volatiles sont simultanément sûres?

Question 4: Veuillez comparer les similitudes et les différences entre volatile et synchronisé.

Question 5: Veuillez expliquer comment Thread Local résout la sécurité de la concurrence?

Question 6: Beaucoup de gens disent que Thread Local doit être utilisé avec prudence. Dites-nous ce que vous en pensez, à quoi dois-je faire attention lorsque j'utilise Thread Local?

……………………

Problèmes liés synchronisés

Question 1: Avez-vous déjà utilisé Synchronized? Quel est son principe?

Question 2: Vous venez de mentionner l'acquisition d'un verrou sur un objet. Qu'est-ce que c'est exactement ce "verrou"? Comment déterminer le verrou d'un objet?

Question 3: Qu'est-ce que la réentrance et pourquoi Synchronized est-il un verrou réentrant? Réentrance

Question 4: Quelles optimisations la JVM apporte-t-elle aux verrous natifs de Java?

Question 5: Pourquoi la synchronisation est-elle un verrou injuste?

Question 6: Qu'est-ce que l'élimination des verrous et le grossissement des verrous?

Question 7: Pourquoi Synchronized est-il un verrou pessimiste? Quel est le principe du verrouillage optimiste? Qu'est-ce que CAS et quelles sont ses caractéristiques?

Question 8: Le verrouillage optimiste est-il nécessairement bon?

d'autres problèmes

Base de connaissances concurrente JAVA

Méthode d'implémentation / création de thread JAVA

4 pools de threads

Cycle de vie du filetage (état)

4 façons de terminer les threads

La différence entre dormir et attendre

La différence entre start et run

Fil d'arrière-plan JAVA

Verrou JAVA

Méthode de fil de base

Changement de contexte de thread

Synchronisation et blocage

Principe du pool de threads

Principe de la file d'attente de blocage JAVA

Utilisation de CyclicBarrier, CountDownLatch, Semaphore

Le rôle du mot-clé volatile (visibilité variable, interdire la réorganisation)

Comment partager des données entre deux threads

Fonction ThreadLocal (stockage local des threads)

La différence entre synchronized et ReentrantLock

Concurrence ConcurrentHashMap

Planification des threads utilisée en Java

Algorithme de planification de processus

Qu'est-ce que CAS (comparaison et échange optimiste de verrouillage du mécanisme de verrouillage)

Qu'est-ce que AQS (Abstract Queue Synchronizer)

Toutes les questions d'entrevue de programmation simultanée ont été combinées dans des documents. En raison de la longueur de l'espace, il est impossible de toutes les télécharger. Les partenaires qui ont besoin d'un document compressé complet peuvent "ajouter mon assistant VX pour l'obtenir gratuitement"

                                                            

Affichage des informations

 

Questions d'entretien à haute fréquence de programmation simultanée: verrouillage réentrant + pool de threads + modèle de mémoire, etc. (y compris les réponses)

 

Questions d'entretien à haute fréquence de programmation simultanée: verrouillage réentrant + pool de threads + modèle de mémoire, etc. (y compris les réponses)

 

Carte du cerveau des connaissances:

Questions d'entretien à haute fréquence de programmation simultanée: verrouillage réentrant + pool de threads + modèle de mémoire, etc. (y compris les réponses)

 

Je ne peux m'empêcher de vouloir me plaindre, les points de connaissance sont nombreux et compliqués. . . . . . . . .

Questions d'entretien à haute fréquence de programmation simultanée: verrouillage réentrant + pool de threads + modèle de mémoire, etc. (y compris les réponses)

Je suppose que tu aimes

Origine blog.csdn.net/a159357445566/article/details/108708515
conseillé
Classement