Maison  >  Article  >  Java  >  Questions d'entrevue courantes multithread Java

Questions d'entrevue courantes multithread Java

(*-*)浩
(*-*)浩original
2019-12-24 15:02:402373parcourir

Questions d'entrevue courantes multithread Java

Quelle est la différence entre le parallélisme et la concurrence ? (Apprentissage recommandé : Questions courantes du test Java )

La réussite signifie que deux événements ou plus se produisent en même temps ;

Le parallélisme correspond à plusieurs événements sur différentes entités, et la concurrence correspond à plusieurs événements sur la même entité.

Traitez plusieurs tâches "simultanément" sur un processeur et plusieurs tâches simultanément sur plusieurs processeurs. Tel que le cluster distribué hadoop.

L'objectif de la programmation simultanée est donc d'utiliser pleinement chaque cœur du processeur pour obtenir les performances de traitement les plus élevées.

Quelle est la différence entre un thread et un processus ?

En bref, un processus est l'unité de base pour l'exécution d'un programme et l'allocation des ressources. Un programme a au moins un processus et un processus a au moins un thread. Le processus dispose d'une unité de mémoire indépendante pendant l'exécution et plusieurs threads partagent des ressources mémoire, réduisant ainsi le nombre de temps de commutation et le rendant plus efficace.

Un thread est une entité d'un processus, l'unité de base de la planification et de la répartition du processeur, et une unité de base qui est plus petite qu'un programme et peut s'exécuter de manière indépendante. Plusieurs threads dans le même processus peuvent s'exécuter simultanément.

Qu'est-ce qu'un thread démon ?

Le thread démon est un thread de service Pour être précis, il sert d'autres threads.

Quelles sont les manières de créer un fil de discussion ?

①. Héritez de la classe Thread pour créer une classe thread

Définissez une sous-classe de la classe Thread et remplacez la méthode run de la classe. Le corps de la méthode run représente. les exigences du fil Tâches terminées. Par conséquent, la méthode run() est appelée le corps d’exécution.

Créez une instance de la sous-classe Thread, c'est-à-dire créez un objet thread.

Appelez la méthode start() de l'objet thread pour démarrer le thread.

②. Créez une classe de thread via l'interface Runnable

Définissez la classe d'implémentation de l'interface exécutable et remplacez la méthode run() de l'interface. La méthode est également le corps d'exécution du thread.

Créez une instance de la classe d'implémentation Runnable et utilisez cette instance comme cible de Thread pour créer un objet Thread. Cet objet Thread est le véritable objet thread.

Appelez la méthode start() de l'objet thread pour démarrer le thread.

③. Créez des threads via Callable et Future

Créez une classe d'implémentation de l'interface Callable et implémentez la méthode call(), qui servira de corps d'exécution du thread et aura une valeur de retour.

Créez une instance de la classe d'implémentation Callable et utilisez la classe FutureTask pour envelopper l'objet Callable. L'objet FutureTask encapsule la valeur de retour de la méthode call() de l'objet Callable.

Utilisez l'objet FutureTask comme cible de l'objet Thread pour créer et démarrer un nouveau fil de discussion.

Appelez la méthode get() de l'objet FutureTask pour obtenir la valeur de retour après l'exécution du sous-thread.

Dites-moi quelle est la différence entre exécutable et appelable ?

C'est une question un peu profonde, et cela montre également l'étendue des connaissances qu'un programmeur Java peut acquérir.

La valeur de retour de la méthode run() dans l'interface Runnable est nulle, et ce qu'elle fait est uniquement d'exécuter le code dans la méthode run()

L'appel( dans le La méthode Callable interface ) a une valeur de retour et est un type générique. Elle peut être utilisée pour obtenir les résultats d'une exécution asynchrone en conjonction avec Future et FutureTask.

Quels sont les statuts des discussions ?

Les threads ont généralement cinq états : créé, prêt, en cours d'exécution, bloqué et mort.

Créer un statut. Lorsque l'objet thread est généré, la méthode de démarrage de l'objet n'est pas appelée, ce qui signifie que le thread est dans l'état de création.

Statut Prêt. Lorsque la méthode de démarrage de l'objet thread est appelée, le thread entre dans l'état prêt, mais à ce moment-là, le planificateur de thread n'a pas défini le thread comme thread actuel et il est à l'état prêt à ce moment-là. Une fois le thread exécuté, il sera également à l'état prêt après son retour d'attente ou de veille.

Statut d'exécution. Le planificateur de threads définit le thread à l'état prêt comme thread actuel. À ce moment, le thread entre dans l'état d'exécution et commence à exécuter le code dans la fonction d'exécution.

Statut de blocage. Lorsqu'un thread est en cours d'exécution, il est suspendu, généralement pour attendre un certain temps (par exemple, une certaine ressource est prête) avant de continuer à s'exécuter. La mise en veille, la suspension, l'attente et d'autres méthodes peuvent provoquer un blocage des threads.

État de mort. Si la méthode run d'un thread se termine ou si la méthode stop est appelée, le thread mourra. Pour un fil qui est mort, vous ne pouvez plus utiliser la méthode start pour le préparer

Quelle est la différence entre sleep() et wait() ?

sleep() : La méthode est une méthode statique de la classe thread (Thread), qui met le thread appelant en état de veille et donne la possibilité d'exécution à d'autres threads une fois le temps de veille terminé. , le thread entre dans l'état prêt et les autres threads se font concurrence pour le temps d'exécution du processeur.

Étant donné que sleep() est une méthode statique, elle ne peut pas modifier le verrouillage machine de l'objet. Lorsque la méthode sleep() est appelée dans un bloc synchronisé, bien que le thread se mette en veille, le verrouillage machine de l'objet n'est pas libéré. . Les autres threads ne peuvent toujours pas accéder à cet objet.

wait() : wait() est une méthode de la classe Object. Lorsqu'un thread exécute la méthode wait, il entre dans un pool d'attente lié à l'objet et libère le verrou machine de l'objet afin que d'autres threads puissent y accéder. vous pouvez réveiller les threads en attente via les méthodes notify et notifyAll

Quelle est la différence entre notify() et notifyAll() ?

Si un thread appelle la méthode wait() d'un objet, le thread sera dans le pool d'attente de l'objet et les threads du pool d'attente ne seront pas en compétition pour le verrou de l'objet.

Lorsqu'un thread appelle la méthode notifyAll() de l'objet (réveille tous les threads d'attente) ou la méthode notify() (réveille un seul thread d'attente de manière aléatoire), le thread réveillé entrera dans le pool de verrouillage de l'objet, les threads dans le pool de verrouillage seront en compétition pour le verrouillage de l'objet.

C'est-à-dire qu'après avoir appelé notify, tant qu'un thread entrera dans le pool de verrouillage à partir du pool d'attente, notifyAll déplacera tous les threads du pool d'objets en attente vers le pool de verrouillage pour attendre la concurrence de verrouillage.

Les threads avec une priorité élevée ont une forte probabilité d'être en compétition pour le verrouillage d'objet. Si un thread n'est pas en compétition pour le verrouillage d'objet, il restera dans le pool de verrouillage uniquement lorsque le thread appelle la méthode wait(). encore une fois, peut-il retourner dans la piscine d'attente.

Le thread en compétition pour le verrouillage d'objet continuera à s'exécuter jusqu'à ce que le bloc de code synchronisé soit exécuté, et il libérera le verrouillage d'objet. À ce moment, les threads du pool de verrouillage continueront à se battre pour le verrouillage d'objet. verrouillage d'objet.

Quelle est la différence entre thread run() et start() ?

Chaque thread termine son opération via la méthode run() correspondant à un objet Thread spécifique. La méthode run() est appelée le corps du thread. Démarrez un thread en appelant la méthode start() de la classe Thread.

méthode start() pour démarrer un thread, réalisant véritablement une opération multithread. À ce stade, il n'est pas nécessaire d'attendre que le code du corps de la méthode d'exécution soit exécuté, et vous pouvez directement continuer à exécuter le code suivant à ce moment, le thread est dans l'état prêt et n'est pas en cours d'exécution ;

Appelez ensuite la méthode run() via cette classe Thread pour terminer son état d'exécution. La méthode run() est ici appelée le corps du thread, qui contient le contenu du thread à exécuter. , et cette terminaison de fil. Le CPU planifie ensuite d'autres threads.

La méthode run() est dans ce fil. C'est juste une fonction dans le fil, pas multithread. Si vous appelez run() directement, cela équivaut en fait à appeler une fonction ordinaire. Si vous utilisez directement la méthode run(), vous devez attendre que la méthode run() termine son exécution avant d'exécuter le code suivant. il n'y a toujours qu'un seul chemin d'exécution et il n'y a aucune caractéristique de thread, donc la méthode start() doit être utilisée à la place de la méthode run() lors d'une exécution multi-thread.

Quelles sont les manières de créer un pool de threads ?

①. newFixedThreadPool(int nThreads)

Créez un pool de threads de longueur fixe et créez un thread chaque fois qu'une tâche est soumise jusqu'à ce que le nombre maximum de pools de threads soit atteint. cette fois, la taille du thread ne changera plus. Lorsqu'un thread se termine en raison d'une erreur inattendue, le pool de threads ajoute un nouveau thread.

②.newCachedThreadPool()

Créez un pool de threads pouvant être mis en cache. Si la taille du pool de threads dépasse la demande de traitement, les threads inactifs seront automatiquement recyclés. Lorsque la demande augmente, les threads inactifs peuvent être recyclés. automatiquement recyclé. Il n'y a aucune limite sur la taille du pool de threads lors de l'ajout de nouveaux threads.

③. newSingleThreadExecutor()

Il s'agit d'un exécuteur à thread unique, qui crée un seul thread de travail pour effectuer des tâches si ce thread se termine anormalement, un nouveau sera créé pour le remplacer. ; it La caractéristique est qu'il peut assurer une exécution en série selon l'ordre des tâches dans la file d'attente.

④. newScheduledThreadPool(int corePoolSize)

Crée un pool de threads de longueur fixe et exécute des tâches de manière retardée ou chronométrée, similaire à Timer.

Quels sont les statuts du pool de threads ?

Le pool de threads a 5 états : En cours d'exécution, Arrêt, Arrêt, Rangement, Terminé.

Schéma de cadre des états de commutation du pool de threads :

Questions dentrevue courantes multithread Java

Les méthodes submit() et exécuté() dans le pool de threads est Quelle est la différence ?

Les paramètres reçus sont différents

submit a une valeur de retour, mais exécuter ne le fait pas

submit facilite la gestion des exceptions

dans programme javaComment assurer la sécurité du fonctionnement multithread ?

La sécurité des threads se reflète dans trois aspects :

Atomicité : fournissant un accès mutuellement exclusif, un seul thread peut opérer sur les données en même temps (atomic , synchronisé);

Visibilité : les modifications apportées à la mémoire principale par un thread peuvent être vues par les autres threads dans le temps, (synchronisé, volatile

Ordre : un thread observe les autres threads) ; l'exécution des instructions dans un thread, en raison de la réorganisation des instructions, est généralement désorganisée (principe de l'arrivée avant).

Quel est le principe de mise à niveau du verrouillage multi-thread ?

En Java, il existe 4 états de verrouillage. Les niveaux de faible à élevé sont : le verrouillage sans état, le verrouillage biaisé, le verrouillage léger et l'état de verrouillage lourd. Ces états changeront progressivement au fur et à mesure de la concurrence. dégénère. Les verrous peuvent être améliorés mais pas dégradés.

Processus illustré de mise à niveau du verrou :

Questions dentrevue courantes multithread Java

Qu'est-ce qu'une impasse ?

L'impasse fait référence à un phénomène de blocage provoqué par deux ou plusieurs processus en compétition pour les ressources ou communiquant entre eux pendant l'exécution, ils seront tous incapables de continuer. À ce moment-là, on dit que le système est dans un état de blocage ou que le système est dans une impasse. Ces processus qui s'attendent toujours les uns les autres sont appelés processus de blocage.

est une erreur au niveau du système d'exploitation et est l'abréviation de processus deadlock. Il a été proposé pour la première fois par Dijkstra en 1965 lors de l'étude de l'algorithme du banquier. C'est le plus difficile à gérer dans les systèmes d'exploitation informatiques et même. dans tout le domaine de la programmation concurrente.

Comment éviter les impasses ?

Quatre conditions nécessaires en cas de blocage :

Condition d'exclusion mutuelle : Un processus ne permet pas à d'autres processus d'accéder aux ressources allouées si d'autres processus y accèdent. ressource, vous ne pouvez qu'attendre que le processus occupant la ressource libère la ressource

Conditions de demande et de rétention : une fois que le processus a obtenu une certaine ressource, il fait une demande pour d'autres ressources, mais la ressource peut être occupée par d'autres processus, cette requête est bloquée, mais elle conserve les ressources qu'elle a obtenues

Condition non privable : fait référence à la ressource que le processus a obtenue, qui ne peut être privée avant que l'utilisation ne soit terminée. utilisé après Libérez-le après utilisation

Conditions d'attente de boucle : fait référence aux quatre conditions après qu'un blocage de processus se produit, et plusieurs processus forment une boucle tête-à-queue en attente d'une relation de ressources

sont nécessaires conditions de blocage. Tant qu'un blocage se produit dans le système, ces conditions doivent être vraies. Tant qu'une des conditions ci-dessus n'est pas remplie, un blocage ne se produira pas.

Comprendre les causes des blocages, en particulier les quatre conditions nécessaires aux blocages, vous pouvez éviter, prévenir et éliminer les blocages dans la mesure du possible.

Par conséquent, en termes de conception du système, de planification des processus, etc., faites attention à la manière d'empêcher l'établissement de ces quatre conditions nécessaires et à la manière de déterminer un algorithme d'allocation de ressources raisonnable pour éviter que les processus n'occupent en permanence les ressources du système. .

De plus, il est également nécessaire d'empêcher les processus d'occuper des ressources lorsqu'ils sont en état d'attente. L’allocation des ressources doit donc être correctement planifiée.

Qu'est-ce que ThreadLocal ? Quels sont les scénarios d’utilisation ?

Les variables locales du thread sont des variables limitées au thread. Elles appartiennent au thread lui-même et ne sont pas partagées entre plusieurs threads. Java fournit la classe ThreadLocal pour prendre en charge les variables locales de thread, ce qui constitue un moyen d'assurer la sécurité des threads.

Mais soyez particulièrement prudent lorsque vous utilisez des variables locales de thread dans un environnement géré (tel qu'un serveur Web), où le cycle de vie du thread de travail est plus long que le cycle de vie de n'importe quelle variable d'application.

Une fois qu'une variable locale du thread n'est pas publiée une fois le travail terminé, les applications Java risquent de subir des fuites de mémoire.

Parlez-moi du principe sous-jacent de mise en œuvre de synchronisé ?

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, et il peut également garantir la visibilité de la mémoire des variables partagées.

Chaque objet en Java peut être utilisé comme verrou, ce qui constitue la base de l'implémentation synchronisée de la synchronisation :

Méthode de synchronisation commune, le verrou est l'objet d'instance actuel

Méthode de synchronisation statique, lock C'est l'objet de classe de la classe actuelle

bloc de méthode synchronisé, et le verrou est l'objet entre parenthèses

Quelle est la différence entre synchronisé et volatile ?

L'essence de volatile est de dire au jvm que la valeur de la variable actuelle dans le registre (mémoire de travail) est incertaine et doit être lue à partir de la mémoire principale, verrouille de manière synchronisée la variable actuelle et ; seul le thread actuel peut le faire. Lors de l'accès à cette variable, les autres threads sont bloqués.

volatile ne peut être utilisé qu'au niveau de la variable ; synchronisé peut être utilisé au niveau de la variable, de la méthode et de la classe.

volatile ne peut réaliser que la visibilité des modifications des variables et ne peut pas garantir l'atomicité tandis que synchronisé peut garantir la visibilité des modifications et l'atomicité des variables.

Volatile ne provoquera pas de blocage de thread ; synchronisé peut provoquer un blocage de thread.

Les variables marquées comme volatiles ne seront pas optimisées par le compilateur ; les variables marquées comme synchronisées peuvent être optimisées par le compilateur.

Quelle est la différence entre synchronisé et verrouillé ?

Tout d'abord, synchronisé est un mot-clé intégré à Java Au niveau jvm, Lock est une classe Java

Synchronized ne peut pas déterminer si l'état du verrouillage est acquis, mais Lock peut déterminer si le verrou est acquis ;

synchronisé libérera automatiquement le verrou (un thread libérera le verrou après l'exécution du code de synchronisation ; le thread b libérera le verrou si une exception se produit pendant l'exécution), Lock doit être libéré manuellement dans finalement (la méthode unlock() libère le verrou), Sinon, il est facile de provoquer un blocage du thread

Utilisez le mot-clé synchronisé pour deux threads 1 et 2. Si le thread actuel est 1 ; obtient le verrou, le thread 2 attendra. Si le thread 1 est bloqué, le thread 2 attendra indéfiniment, et le verrou Lock n'attendra pas nécessairement. Si le verrou ne peut pas être obtenu, le thread peut se terminer sans attendre

Le verrouillage synchronisé peut être répété. Saisissant, ininterrompu. , et injuste, tandis que les verrous Lock sont réentrants, jugeables et équitables (les deux sont possibles)

Les verrous Lock conviennent aux problèmes de synchronisation avec une grande quantité de code synchronisé, et les verrous synchronisés conviennent à de petites quantités de code ; problèmes de synchronisation.

Quelle est la différence entre synchronisé et ReentrantLock ?

synchronized est le même mot-clé que if, else, for et while, et ReentrantLock est une classe. C'est la différence essentielle entre les deux.

Puisque ReentrantLock est une classe, elle fournit des fonctionnalités de plus en plus flexibles que synchronisées. Elle peut être héritée, peut avoir des méthodes et peut avoir diverses variables de classe. Elle est plus extensible que synchronisée. 🎜>

ReentrantLock peut définir le temps d'attente pour l'acquisition des verrous, évitant ainsi les blocages

ReentrantLock peut obtenir des informations sur divers verrous

ReentrantLock peut mettre en œuvre de manière flexible plusieurs notifications

De plus, les mécanismes de verrouillage des deux sont en réalité différents : ReentrantLock appelle la méthode park d'Unsafe pour verrouiller en bas, tandis que synchronisé devrait opérer sur le mot de marque dans l'en-tête de l'objet.

Parlez-moi du principe atomique ?

La caractéristique de base des classes du package Atomic est que dans un environnement multithread, lorsque plusieurs threads opèrent sur une seule variable (y compris les types de base et les types de référence) en même temps, ils sont exclusifs, c'est-à-dire que lorsque plusieurs threads mettent à jour la valeur de cette variable en même temps, un seul thread peut réussir et le thread qui échoue peut continuer à essayer comme un verrou tournant jusqu'à ce que l'exécution réussisse.

Les méthodes principales de la série de classes Atomic appelleront plusieurs méthodes locales dans la classe non sécurisée. Une chose que nous devons d'abord connaître est la classe Unsafe, dont le nom complet est : sun.misc.Unsafe. Cette classe contient un grand nombre d'opérations sur le code C, y compris de nombreuses allocations directes de mémoire et des appels à des opérations atomiques. est marqué comme non sécurisé, je vous dis qu'un grand nombre d'appels de méthodes comporteront des risques de sécurité et que vous devez les utiliser avec prudence, sinon cela entraînera de graves conséquences. Par exemple, lors de l'allocation de mémoire de manière non sécurisée, si vous spécifiez certaines zones, cela peut provoquer des problèmes similaires à ceux du C++. Le pointeur franchit la frontière vers d'autres processus.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn