Heim  >  Artikel  >  Java  >  Fragen zum Java-Multithreading-Interview, die es wert sind, gesammelt zu werden (mit Antworten)

Fragen zum Java-Multithreading-Interview, die es wert sind, gesammelt zu werden (mit Antworten)

青灯夜游
青灯夜游nach vorne
2019-11-25 15:21:582293Durchsuche

Dieser Artikel fasst einige Fragen und Antworten zum Java-Multithreading für Sie zusammen. Ich hoffe, dass er für alle hilfreich ist.

Fragen zum Java-Multithreading-Interview, die es wert sind, gesammelt zu werden (mit Antworten)

Was ist ein Thread?

Thread ist die kleinste Einheit, die das Betriebssystem ausführen kann. Er ist im Prozess enthalten und die eigentliche Betriebseinheit im Prozess. Programmierer können es für die Multiprozessorprogrammierung verwenden, und Sie können Multithreading verwenden, um rechenintensive Aufgaben zu beschleunigen. Wenn es beispielsweise 100 Millisekunden dauert, bis ein Thread eine Aufgabe erledigt, dann dauert es nur 10 Millisekunden, bis zehn Threads die Aufgabe erledigt haben. Java bietet eine hervorragende Unterstützung für Multithreading auf Sprachebene, was ebenfalls ein gutes Verkaufsargument ist.

2) Was ist der Unterschied zwischen Thread und Prozess?

Threads sind eine Teilmenge von Prozessen. Ein Prozess kann viele Threads haben und jeder Thread führt unterschiedliche Aufgaben parallel aus. Verschiedene Prozesse nutzen unterschiedliche Speicherplätze und alle Threads teilen sich denselben Speicherplatz. Verwechseln Sie dies nicht mit dem Stapelspeicher. Jeder Thread verfügt über einen eigenen Stapelspeicher zum Speichern lokaler Daten.

3) Wie implementiert man Threads in Java?

Auf Sprachebene gibt es zwei Möglichkeiten. Eine Instanz der java.lang.Thread-Klasse ist ein Thread, sie muss jedoch zur Ausführung die java.lang.Runnable-Schnittstelle aufrufen. Da die Thread-Klasse selbst die aufgerufene Runnable-Schnittstelle ist, können Sie die java.lang.Thread-Klasse erben oder rufen Sie direkt die Runnable-Schnittstelle auf, um sie zu überschreiben. Schreiben Sie die run()-Methode, um Threads zu implementieren.

4) Runnable oder Thread verwenden?

Diese Frage ist eine Fortsetzung der vorherigen Frage. Jeder weiß, dass wir Threads implementieren können, indem wir die Thread-Klasse erben oder die Runnable-Schnittstelle aufrufen. Die Frage ist, welche Methode besser ist. Wann wird es verwendet? Diese Frage lässt sich leicht beantworten, wenn Sie wissen, dass Java die Mehrfachvererbung von Klassen nicht unterstützt, Ihnen aber den Aufruf mehrerer Schnittstellen ermöglicht. Wenn Sie also von anderen Klassen erben möchten, müssen Sie natürlich das Runnable-Interface aufrufen.

6) Was ist der Unterschied zwischen den Methoden start() und run() in der Thread-Klasse?

Diese Frage wird oft gestellt, kann aber dennoch das Verständnis des Interviewers für das Java-Thread-Modell unterscheiden. Die start()-Methode wird verwendet, um einen neu erstellten Thread zu starten, und start() ruft intern die run()-Methode auf, was einen anderen Effekt hat als der direkte Aufruf der run()-Methode. Wenn Sie die Methode run() aufrufen, wird sie nur im ursprünglichen Thread aufgerufen. Wenn kein neuer Thread gestartet wird, startet die Methode start() einen neuen Thread.

7) Was ist der Unterschied zwischen Runnable und Callable in Java?

Runnable und Callable stellen beide Aufgaben dar, die in verschiedenen Threads ausgeführt werden sollen. Runnable ist seit JDK1.0 verfügbar und Callable wurde in JDK1.5 hinzugefügt. Der Hauptunterschied zwischen ihnen besteht darin, dass die call()-Methode von Callable Werte zurückgeben und Ausnahmen auslösen kann, während die run()-Methode von Runnable diese Funktionen nicht hat. Callable kann ein mit Berechnungsergebnissen geladenes Future-Objekt zurückgeben.

8) Was ist der Unterschied zwischen CyclicBarrier und CountDownLatch in Java?

Sowohl CyclicBarrier als auch CountDownLatch können verwendet werden, um eine Gruppe von Threads auf andere Threads warten zu lassen. Im Gegensatz zu CyclicBarrier kann CountdownLatch nicht wiederverwendet werden.

9) Was ist das Java-Speichermodell?

Das Java-Speichermodell spezifiziert und leitet Java-Programme an, sich deterministisch über verschiedene Speicherarchitekturen, CPUs und Betriebssysteme hinweg zu verhalten. Dies ist besonders wichtig in Situationen mit mehreren Threads. Das Java-Speichermodell bietet eine Garantie dafür, dass von einem Thread vorgenommene Änderungen für andere Threads sichtbar sind und zwischen ihnen eine Vorrangbeziehung besteht. Diese Beziehung definiert einige Regeln, damit Programmierer beim gleichzeitigen Programmieren klarer denken können. Die Look-Ahead-Beziehung stellt beispielsweise sicher, dass:

  • Der Code im Thread der Reihe nach ausgeführt werden kann. Dies wird als Programmreihenfolgeregel bezeichnet.
  • Für dieselbe Sperre muss ein Entsperrvorgang vor einem anderen Sperrvorgang erfolgen, der später erfolgt, auch Monitor-Sperrregel genannt.
  • Der vorherige flüchtige Schreibvorgang geht dem nächsten flüchtigen Lesevorgang voraus, auch Regel für flüchtige Variablen genannt.
  • Jede Operation innerhalb eines Threads muss nach dem start()-Aufruf dieses Threads aufgerufen werden, auch Thread-Startregel genannt.
  • Alle Vorgänge eines Threads werden ausgeführt, bevor der Thread gemäß der Thread-Beendigungsregel beendet wird.
  • Der Finalisierungsvorgang eines Objekts muss abgeschlossen sein, nachdem das Objekt erstellt wurde. Dies wird auch als Objektbeendigungsregel bezeichnet.
  • Transportierbarkeit

Ich empfehle Ihnen dringend, Kapitel 16 von „Java Concurrent Programming Practice“ zu lesen, um Ihr Verständnis des Java-Speichermodells zu vertiefen.

10) Was sind flüchtige Variablen in Java?

volatile ist ein spezieller Modifikator, der nur von Mitgliedsvariablen verwendet werden kann. Da es in Java-Parallelprogrammen keine Synchronisierungsklassen gibt, sind Multithread-Operationen an Mitgliedsvariablen für andere Threads transparent. Flüchtige Variablen können garantieren, dass der nächste Lesevorgang nach dem vorherigen Schreibvorgang erfolgt. Dies ist die Regel für flüchtige Variablen in der vorherigen Frage.

11) Was ist Thread-Sicherheit? Ist Vector eine Thread-sichere Klasse?

Wenn in dem Prozess, in dem sich Ihr Code befindet, mehrere Threads gleichzeitig ausgeführt werden, führen diese Threads diesen Code möglicherweise gleichzeitig aus. Wenn die Ergebnisse jedes Laufs mit denen von Single-Thread-Läufen übereinstimmen und die Werte anderer Variablen mit den Erwartungen übereinstimmen, ist dies Thread-sicher. Eine Thread-sichere Zählerklasse verursacht keine Berechnungsfehler, wenn dasselbe Instanzobjekt von mehreren Threads verwendet wird. Natürlich können Sie Sammlungsklassen in zwei Gruppen einteilen: Thread-sichere und nicht Thread-sichere. Vector verwendet synchronisierte Methoden, um Thread-Sicherheit zu erreichen, während ArrayList, das ihm ähnlich ist, nicht Thread-sicher ist.

12) Was ist eine Racebedingung in Java? Geben Sie ein Beispiel.

Rennbedingungen verursachen unter gleichzeitigen Bedingungen einige Fehler im Programm. Race-Bedingungen treten auf, wenn mehrere Threads um einige Ressourcen konkurrieren. Wenn das zuerst auszuführende Programm nicht konkurriert und später ausgeführt wird, treten im gesamten Programm einige unsichere Fehler auf. Solche Fehler sind aufgrund der zufälligen Konkurrenz zwischen Threads schwer zu finden und treten immer wieder auf.

13) Wie stoppe ich einen Thread in Java?

Java bietet eine umfangreiche API, jedoch keine API zum Stoppen von Threads. JDK 1.0 verfügte ursprünglich über einige Steuerungsmethoden wie stop(), suspend() und resume(), diese wurden jedoch in nachfolgenden JDK-Versionen aufgrund potenzieller Deadlock-Bedrohungen veraltet. Danach stellten die Entwickler der Java-API keine kompatiblen und Thread-basierten Methoden zur Verfügung. sichere Möglichkeit, einen Thread zu stoppen. Der Thread wird automatisch beendet, wenn die Methode run() oder call() ausgeführt wird. Wenn Sie einen Thread manuell beenden möchten, können Sie eine flüchtige boolesche Variable verwenden, um die Schleife der Methode run() zu verlassen oder die Aufgabe abzubrechen, um den Thread zu unterbrechen .

14) Was passiert, wenn eine Ausnahme auftritt, während ein Thread ausgeführt wird?

Dies ist eine sehr knifflige Java-Interviewfrage, auf die ich in einem Interview gestoßen bin. Einfach ausgedrückt: Wenn die Ausnahme nicht abgefangen wird, wird die Ausführung des Threads gestoppt. Thread.UncaughtExceptionHandler ist eine eingebettete Schnittstelle, die zur Behandlung plötzlicher Thread-Unterbrechungen verwendet wird, die durch nicht abgefangene Ausnahmen verursacht werden. Wenn eine nicht abgefangene Ausnahme zur Unterbrechung eines Threads führt, verwendet die JVM Thread.getUncaughtExceptionHandler(), um den UncaughtExceptionHandler des Threads abzufragen und den Thread und die Ausnahme als Parameter an die uncaughtException()-Methode des Handlers zur Verarbeitung zu übergeben.

15) Wie teile ich Daten zwischen zwei Threads?

Sie können dies durch gemeinsame Objekte oder die Verwendung gleichzeitiger Datenstrukturen wie Blockierungswarteschlangen erreichen. Dieses Tutorial „Java Inter-Thread-Kommunikation“ (einschließlich der gemeinsamen Nutzung von Objekten zwischen zwei Threads) verwendet die Methoden „wait“ und „notify“, um das Producer-Consumer-Modell zu implementieren.

16) Was ist der Unterschied zwischen notify und notifyAll in Java?

Dies ist eine weitere knifflige Frage, da mehrere Threads auf eine einzelne Monitorsperre warten können. Die Entwickler der Java-API stellen einige Methoden bereit, um sie zu benachrichtigen, wenn sich die Wartebedingungen ändern, diese Methoden sind jedoch nicht vollständig umgesetzt. Die notify()-Methode kann einen bestimmten Thread nicht aufwecken, daher ist sie nur nützlich, wenn ein Thread wartet. Und notifyAll() weckt alle Threads auf und ermöglicht ihnen, um die Sperre zu konkurrieren, um sicherzustellen, dass mindestens ein Thread weiter ausgeführt werden kann.

17) Warum sind die Methoden „wait“, „notify“ und „notifyAll“ nicht in der Thread-Klasse?

Dies ist eine designbezogene Frage, die die Ansichten des Interviewers zu bestehenden Systemen und einigen häufigen, aber scheinbar unvernünftigen Dingen untersucht. Bei der Beantwortung dieser Fragen müssen Sie erklären, warum es sinnvoll ist, diese Methoden in die Object-Klasse einzufügen, und warum nicht, sie in die Thread-Klasse einzufügen. Ein offensichtlicher Grund ist, dass die von JAVA bereitgestellten Sperren auf der Objektebene und nicht auf der Thread-Ebene liegen. Jedes Objekt verfügt über eine Sperre und wird über den Thread abgerufen. Wenn der Thread auf eine Sperre warten muss, ist es sinnvoll, die Methode wait() im Objekt aufzurufen. Wenn die Methode wait() in der Thread-Klasse definiert ist, ist nicht offensichtlich, auf welche Sperre der Thread wartet. Einfach ausgedrückt: Da Wait, Notify und NotifyAll Vorgänge auf Sperrebene sind, werden sie in der Object-Klasse definiert, da Sperren zu Objekten gehören.

18) Was ist eine ThreadLocal-Variable?

ThreadLocal ist eine spezielle Variable in Java. Jeder Thread verfügt über ein ThreadLocal, was bedeutet, dass jeder Thread seine eigene unabhängige Variable hat und Race Conditions vollständig eliminiert werden. Dies ist eine gute Möglichkeit, Thread-Sicherheit für Objekte zu erreichen, deren Erstellung teuer ist. Sie können beispielsweise ThreadLocal verwenden, um SimpleDateFormat-Thread-sicher zu machen, da die Erstellung dieser Klasse teuer ist und für jeden Aufruf die Erstellung einer anderen Instanz erforderlich ist, sodass es sich nicht lohnt, sie einzubauen lokaler Bereich Wenn jeder Thread damit eine eigene, eindeutige Kopie der Variablen erhält, wird die Effizienz erheblich verbessert. Erstens wird die Anzahl der erstellten teuren Objekte durch Wiederverwendung reduziert. Zweitens gewinnen Sie Thread-Sicherheit, ohne teure Synchronisierung oder Unveränderlichkeit zu verwenden. Ein weiteres gutes Beispiel für Thread-lokale Variablen ist die ThreadLocalRandom-Klasse, die die Anzahl der kostspieligen Random-Objekte reduziert, die in einer Multithread-Umgebung erstellt werden müssen.

19) Was ist FutureTask?

In gleichzeitigen Java-Programmen stellt FutureTask einen asynchronen Vorgang dar, der abgebrochen werden kann. Es verfügt über Methoden wie das Starten und Abbrechen von Vorgängen, das Abfragen, ob Vorgänge abgeschlossen sind, und das Abrufen von Vorgangsergebnissen. Das Ergebnis kann erst abgerufen werden, wenn der Vorgang abgeschlossen ist. Wenn der Vorgang nicht abgeschlossen ist, wird die Get-Methode blockiert. Ein FutureTask-Objekt kann Objekte umschließen, die Callable und Runnable aufrufen. Da FutureTask auch die Runnable-Schnittstelle aufruft, kann es zur Ausführung an den Executor übermittelt werden.

20) Was ist der Unterschied zwischen den Methoden interrupted und isInterruptedd in Java?

Der Hauptunterschied zwischen interrupted() und isInterrupted() besteht darin, dass ersteres den Interrupt-Status löscht und letzteres nicht. Der Interrupt-Mechanismus des Java-Multithreadings wird mithilfe interner Flags implementiert. Durch den Aufruf von Thread.interrupt() zum Unterbrechen eines Threads wird das Interrupt-Flag auf true gesetzt. Wenn der Interrupt-Thread die statische Methode Thread.interrupted () aufruft, um den Interrupt-Status zu überprüfen, wird der Interrupt-Status gelöscht. Die nicht statische Methode isInterrupted() wird verwendet, um den Interrupt-Status anderer Threads abzufragen und ändert die Interrupt-Status-ID nicht. Einfach ausgedrückt: Jede Methode, die eine InterruptedException auslöst, löscht den Interrupt-Status. In jedem Fall kann der Interrupt-Status eines Threads durch andere Threads geändert werden, die Interrupts aufrufen.

21) Warum werden die Wait- und Notify-Methoden in synchronisierten Blöcken aufgerufen?

Hauptsächlich, weil die Java-API dies vorschreibt. Wenn Sie dies nicht tun, löst Ihr Code eine IllegalMonitorStateException aus. Ein weiterer Grund besteht darin, Race-Bedingungen zwischen Warten und Benachrichtigen zu vermeiden.

22) Warum sollten Sie Wartebedingungen in einer Schleife überprüfen?

Threads im Wartezustand erhalten möglicherweise falsche Warnungen und falsche Weckvorgänge, wenn sie nicht in einer Schleife überprüft werden Wenn Sie eine Bedingung angeben, wird das Programm beendet, wenn die Endbedingung nicht erfüllt ist. Wenn ein wartender Thread aufwacht, kann daher nicht davon ausgegangen werden, dass sein ursprünglicher Wartezustand noch gültig ist. Er kann sich in der Zeit nach dem Aufruf der notify()-Methode und vor dem Aufwachen des wartenden Threads ändern. Aus diesem Grund funktioniert die Verwendung der Methode „wait()“ in einer Schleife besser. Sie können in Eclipse eine Vorlage erstellen, um „wait and notify“ aufzurufen, um es auszuprobieren. Wenn Sie mehr über dieses Problem erfahren möchten, empfehle ich die Lektüre des Kapitels „Threads und Synchronisierung“ im Buch „Effective Java“.

23) Was ist der Unterschied zwischen synchronisierten Sammlungen und gleichzeitigen Sammlungen in Java?

Sowohl synchronisierte Sammlungen als auch gleichzeitige Sammlungen bieten geeignete threadsichere Sammlungen für Multithreading und Parallelität, gleichzeitige Sammlungen sind jedoch skalierbarer. Vor Java 1.5 konnten Programmierer nur synchronisierte Sammlungen verwenden, was bei der Multithread-Parallelität zu Konflikten führen und die Skalierbarkeit des Systems beeinträchtigen würde. Mit Java 5 wurden gleichzeitige Sammlungen wie ConcurrentHashMap eingeführt, die nicht nur Thread-Sicherheit bieten, sondern auch die Skalierbarkeit durch moderne Techniken wie Sperrentrennung und interne Partitionierung verbessern.

24) Was ist der Unterschied zwischen Heap und Stack in Java?

Warum wird diese Frage als Interviewfrage zu Multithreading und Parallelität klassifiziert? Weil der Stapel ein Speicherbereich ist, der eng mit Threads verbunden ist. Jeder Thread verfügt über einen eigenen Stapelspeicher, der zum Speichern lokaler Variablen, Methodenparameter und Stapelaufrufe verwendet wird. Variablen, die in einem Thread gespeichert sind, sind für andere Threads nicht sichtbar. Der Heap ist ein gemeinsamer Speicherbereich, der von allen Threads gemeinsam genutzt wird. Alle Objekte werden im Heap erstellt, um die Effizienz zu verbessern. Wenn mehrere Threads diese Variable verwenden, kann dies zu Problemen führen. Der Thread muss vom Hauptstapel aus starten und den Wert einer Variablen aus dem Speicher lesen.

25) Was ist ein Thread-Pool? Warum es verwenden?

Das Erstellen von Threads kostet teure Ressourcen und Zeit. Wenn Threads erst erstellt werden, nachdem eine Aufgabe eintrifft, wird die Antwortzeit länger und die Anzahl der Threads, die von einem Prozess erstellt werden können, ist begrenzt. Um diese Probleme zu vermeiden, werden mehrere Threads erstellt, die beim Start des Programms auf die Verarbeitung reagieren. Sie werden Thread-Pools genannt, und die darin enthaltenen Threads werden Arbeits-Threads genannt. Ab JDK1.5 stellt die Java-API das Executor-Framework bereit, sodass Sie verschiedene Thread-Pools erstellen können. Beispielsweise verarbeitet ein einzelner Thread-Pool jeweils eine Aufgabe; eine feste Anzahl von Thread-Pools oder ein Cache-Thread-Pool (ein erweiterbarer Thread-Pool, der für Programme mit vielen kurzlebigen Aufgaben geeignet ist).

26) Wie schreibe ich Code, um das Producer-Consumer-Problem zu lösen?

In Wirklichkeit gehören viele der Threading-Probleme, die Sie lösen, zum Produzenten-Konsumenten-Modell, bei dem ein Thread Aufgaben erstellt, die andere Threads nutzen können. Sie müssen wissen, wie zwischen Threads kommuniziert wird, um dieses Problem zu lösen . Die untergeordnete Methode ist die Verwendung von „wait“ und „notify“, um dieses Problem zu lösen. Die bessere Methode ist die Verwendung von Semaphore oder BlockingQueue zur Implementierung des Producer-Consumer-Modells.

27) Wie vermeide ich einen Deadlock?


Deadlock im Java-Multithreading
Deadlock bezieht sich auf eine Situation, die dadurch verursacht wird, dass zwei oder mehr Prozesse während der Ausführung um Ressourcen konkurrieren in der Lage sein, ohne äußere Gewalt voranzukommen. Dies ist ein ernstes Problem, da ein Deadlock dazu führt, dass Ihr Programm hängen bleibt und die Aufgabe nicht abgeschlossen werden kann. Die folgenden vier Bedingungen müssen erfüllt sein, damit ein Deadlock auftritt:

  • Bedingung zum gegenseitigen Ausschluss: eine Ressource kann jeweils nur verwendet werden. Kann von einem Prozess verwendet werden.
  • Anforderungs- und Haltebedingungen: Wenn ein Prozess aufgrund der Anforderung von Ressourcen blockiert wird, behält er die erhaltenen Ressourcen.
  • Nicht-Entzugsbedingung: Ressourcen, die ein Prozess erhalten hat, können nicht gewaltsam entzogen werden, bevor sie aufgebraucht sind.
  • Schleifenwartezustand: Mehrere Prozesse bilden eine Kopf-an-Ende-Schleife, die auf eine Ressourcenbeziehung wartet.

Der einfachste Weg, einen Deadlock zu vermeiden, besteht darin, zirkuläre Wartebedingungen zu verhindern, Flags zu setzen und alle Ressourcen im System zu sortieren und festzulegen, dass alle Prozesse Ressourcen in einer bestimmten Reihenfolge (aufsteigend oder absteigend) beantragen müssen ) Führen Sie Vorgänge aus, um einen Deadlock zu vermeiden.

28) Was ist der Unterschied zwischen Livelock und Deadlock in Java?

Dies ist eine Erweiterung der obigen Frage. Der Unterschied besteht darin, dass sich der Status des Threads oder Prozesses in Livelock ständig ändert . Ein realistisches Beispiel für Livelock ist, wenn sich zwei Personen in einem engen Korridor treffen. Beide versuchen, einander auszuweichen, damit der andere passieren kann, aber weil die Ausweichrichtungen gleich sind, kann am Ende niemand durch den Korridor gehen. Einfach ausgedrückt besteht der Hauptunterschied zwischen Livelock und Deadlock darin, dass sich bei ersterem der Status des Prozesses ändern kann, die Ausführung jedoch nicht fortgesetzt werden kann.

29) Wie erkennt man, ob ein Thread eine Sperre besitzt?

Dass wir erkennen können, ob ein Thread eine Sperre besitzt, wusste ich erst, als ich an einem Telefoninterview teilnahm. In java.lang.Thread gibt es eine Methode namens „holdsLock()“, die genau dann „true“ zurückgibt, wenn der aktuelle Thread eine Sperre für ein bestimmtes Objekt hält.

30) Wie bekommt man den Thread-Stack in Java?

Es gibt mehrere Möglichkeiten, den Thread-Stack eines Java-Prozesses für verschiedene Betriebssysteme abzurufen. Wenn Sie den Thread-Stack erhalten, speichert die JVM den Status aller Threads in einer Protokolldatei oder gibt ihn an die Konsole aus. Unter Windows können Sie die Tastenkombination Strg + Pause verwenden, um den Thread-Stack abzurufen, und unter Linux den Befehl kill -3 verwenden. Sie können es auch mit dem Tool jstack abrufen, das mit der Thread-ID arbeitet. Sie können das Tool jps verwenden, um die ID zu ermitteln.

31) Welcher Parameter wird in JVM verwendet, um die Stapelgröße des Threads zu steuern?

Diese Frage ist sehr einfach Stapelgröße des Threads.

32) Was ist der Unterschied zwischen synchronisiert und ReentrantLock in Java?

Java konnte den gegenseitigen Ausschluss in der Vergangenheit lange Zeit nur durch das synchronisierte Schlüsselwort erreichen, was einige Mängel aufweist. Sie können beispielsweise keine Methoden oder Blockgrenzen außerhalb der Sperre erweitern, Sie können beim Versuch, die Sperre zu erhalten, nicht auf halbem Weg abbrechen usw. Java 5 bietet eine komplexere Steuerung über die Lock-Schnittstelle, um diese Probleme zu lösen. Die ReentrantLock-Klasse implementiert Lock, das die gleiche Parallelität und Speichersemantik wie synchronisiert hat, aber auch erweiterbar ist.

33) Es gibt drei Threads T1, T2 und T3. Wie kann sichergestellt werden, dass sie in der richtigen Reihenfolge ausgeführt werden?

Beim Multithreading gibt es viele Möglichkeiten, Threads in einer bestimmten Reihenfolge ausführen zu lassen. Sie können die Methode „join()“ der Thread-Klasse verwenden, um einen anderen Thread in einem Thread zu starten Thread schließt den Thread ab und fährt mit der Implementierung fort. Um die Reihenfolge der drei Threads sicherzustellen, sollten Sie den letzten Thread zuerst starten (T3 ruft T2 auf, T2 ruft T1 auf), sodass T1 zuerst und T3 zuletzt beendet wird.

34) Welche Funktion hat die Yield-Methode in der Thread-Klasse?

Die Yield-Methode kann das aktuell ausgeführte Thread-Objekt anhalten und die Ausführung anderer Threads mit derselben Priorität zulassen. Es handelt sich um eine statische Methode, die nur garantiert, dass der aktuelle Thread die CPU-Belegung aufgibt, nicht jedoch, dass andere Threads die CPU belegen können. Der Thread, der yield() ausführt, kann unmittelbar nach Eintritt in den Pausenzustand erneut ausgeführt werden.

35) Was ist die Parallelität von ConcurrentHashMap in Java?

ConcurrentHashMap unterteilt die eigentliche Karte in mehrere Teile, um ihre Skalierbarkeit und Thread-Sicherheit zu erreichen. Diese Aufteilung wird mithilfe der Parallelität erreicht, einem optionalen Parameter des ConcurrentHashMap-Klassenkonstruktors mit einem Standardwert von 16, um Konflikte in Multithread-Situationen zu vermeiden.

36) Was ist Semaphor in Java?

Semaphore in Java ist eine neue Synchronisationsklasse, die ein Zählsignal ist. Konzeptionell verwaltet ein Semaphor eine autorisierte Sammlung. Bei Bedarf blockiert jeder acquire(), bis die Berechtigung verfügbar ist, und ruft dann die Berechtigung ab. Jedes release() fügt eine Berechtigung hinzu und gibt dadurch möglicherweise einen blockierenden Acquirer frei. Anstatt tatsächliche Lizenzobjekte zu verwenden, zählt Semaphore jedoch nur die Anzahl der verfügbaren Lizenzen und ergreift entsprechende Maßnahmen. Semaphore werden häufig in Multithread-Code verwendet, beispielsweise in Datenbankverbindungspools.

37) Wenn die Thread-Pool-Warteschlange voll ist, wenn Sie die Aufgabe senden. Was passiert, wenn das Treffen stattfindet?

Dies ist eine knifflige Frage, und viele Programmierer werden denken, dass die Aufgabe blockiert wird, bis ein Platz in der Thread-Pool-Warteschlange vorhanden ist. Wenn die Ausführung einer Aufgabe nicht geplant werden kann, löst die Methode „submit()“ von ThreadPoolExecutor tatsächlich eine „RejectedExecutionException“ aus.

38) Was ist der Unterschied zwischen den Methoden „submit()“ und „execute()“ im Java-Thread-Pool?

Beide Methoden können Aufgaben an den Thread-Pool senden. Der Rückgabetyp der Methode „execute()“ ist void, der in der Executor-Schnittstelle definiert ist, und die Methode „submit()“ kann einen Future-Bestand zurückgeben die Berechnungsergebnisse. Objekt, das in der ExecutorService-Schnittstelle definiert ist und die Executor-Schnittstelle erweitert. Andere Thread-Pool-Klassen wie ThreadPoolExecutor und ScheduledThreadPoolExecutor verfügen über diese Methoden.

39) Was ist eine Blockierungsmethode?

Die Blockierungsmethode bedeutet, dass das Programm auf den Abschluss der Methode wartet, ohne etwas anderes zu tun. Die Methode „accept()“ von ServerSocket wartet darauf, dass der Client eine Verbindung herstellt. Das Blockieren bedeutet hier, dass der aktuelle Thread angehalten wird, bevor das Aufrufergebnis zurückgegeben wird, und erst nach Erhalt des Ergebnisses zurückkehrt. Darüber hinaus gibt es asynchrone und nicht blockierende Methoden, die vor Abschluss der Aufgabe zurückkehren.

40) Ist Swing Thread-sicher? Warum?

Sie können mit Sicherheit antworten, dass Swing nicht threadsicher ist, aber Sie sollten den Grund für Ihre Antwort erläutern, auch wenn der Interviewer Sie nicht nach dem Grund fragt. Wenn wir sagen, dass Swing nicht threadsicher ist, erwähnen wir häufig seine Komponenten, die nicht in Multithreads geändert werden können. Alle Aktualisierungen von GUI-Komponenten müssen im AWT-Thread abgeschlossen werden, und Swing bietet zwei Rückrufmethoden: synchron und asynchron . zum Aktualisieren.

41) Was ist der Unterschied zwischen invokeAndWait und invokeLater in Java?

Diese beiden Methoden werden von der Swing-API für Java-Entwickler bereitgestellt, um GUI-Komponenten aus dem aktuellen Thread statt aus dem Event-Dispatch-Thread zu aktualisieren. InvokeAndWait() aktualisiert GUI-Komponenten, wie zum Beispiel einen Fortschrittsbalken, synchron. Sobald der Fortschritt aktualisiert ist, muss sich auch der Fortschrittsbalken entsprechend ändern. Wenn der Fortschritt von mehreren Threads verfolgt wird, rufen Sie die Methode invokeAndWait() auf, um den Event-Dispatch-Thread aufzufordern, die Komponente entsprechend zu aktualisieren. Die Methode invokeLater() ruft die Update-Komponente asynchron auf.

42) Welche Methoden in der Swing-API sind threadsicher?

In dieser Frage wurde auch Swing und Thread-Sicherheit erwähnt. Obwohl die Komponente nicht threadsicher ist, gibt es einige Methoden, die von mehreren Threads sicher aufgerufen werden können, wie z. B. repaint(), revalidate(). Die setText()-Methode von JTextComponent und die insert()- und append()-Methoden von JTextArea sind ebenfalls threadsicher.

43) Wie erstelle ich ein unveränderliches Objekt in Java?

Dieses Problem scheint nichts mit Multithreading zu tun zu haben, aber Unveränderlichkeit kann dabei helfen, bereits komplexe gleichzeitige Programme zu vereinfachen. Unveränderliche Objekte können ohne Synchronisierung gemeinsam genutzt werden, wodurch der Synchronisierungsaufwand für den gleichzeitigen Zugriff auf das Objekt reduziert wird. Allerdings verfügt Java nicht über die Annotation @Immutable. Um eine unveränderliche Klasse zu erstellen, müssen Sie die folgenden Schritte implementieren: Initialisieren Sie alle Mitglieder über die Konstruktormethode, stellen Sie keine Setter-Methoden für Variablen bereit und deklarieren Sie alle Mitglieder als privat, also direkt Beim Zugriff auf diese Mitglieder wird in der Getter-Methode nicht direkt das Objekt selbst zurückgegeben, sondern das Objekt geklont und eine Kopie des Objekts zurückgegeben. Mein Artikel „Wie man ein Objekt in Java unveränderlich macht“ enthält eine ausführliche Anleitung. Nachdem Sie ihn gelesen haben, können Sie sicher sein.

44) Was ist ReadWriteLock in Java?

Im Allgemeinen sind Lese-/Schreibsperren das Ergebnis der Sperrentrennungstechnologie, die zur Verbesserung der Leistung gleichzeitiger Programme eingesetzt wird. ReadWriteLock in Java ist eine neue Schnittstelle in Java 5. Ein ReadWriteLock verwaltet ein Paar zugehöriger Sperren, eine für schreibgeschützte Vorgänge und eine für Schreibvorgänge. Wenn kein Schreibthread vorhanden ist, kann eine Lesesperre von mehreren Lesethreads gleichzeitig gehalten werden. Schreibsperren sind exklusiv. Sie können ReentrantReadWriteLock im JDK verwenden, um diese Regel zu implementieren. Es unterstützt bis zu 65535 Schreibsperren und 65535 Lesesperren.

45) Was ist eine Besetztschleife beim Multithreading?

Eine Besetztschleife liegt vor, wenn Programmierer im Gegensatz zu den herkömmlichen Methoden eine Schleife verwenden, um einen Thread warten zu lassen wait(), sleep() oder yield() geben alle die CPU-Steuerung auf, und die Busy-Schleife gibt die CPU nicht auf, sondern führt eine leere Schleife aus. Der Zweck besteht darin, den CPU-Cache zu erhalten. In einem Multi-Core-System kann ein wartender Thread beim Aufwachen auf einem anderen Kern ausgeführt werden, wodurch der Cache neu aufgebaut wird. Es kann verwendet werden, um einen Neuaufbau des Caches zu vermeiden und die Wartezeit für den Neuaufbau zu verkürzen.

46) Was ist der Unterschied zwischen flüchtigen Variablen und atomaren Variablen?

Das ist eine interessante Frage. Zunächst sehen flüchtige Variablen und atomare Variablen ähnlich aus, ihre Funktionen sind jedoch unterschiedlich. Flüchtige Variablen können eine Look-Ahead-Beziehung sicherstellen, das heißt, ein Schreibvorgang findet vor einem nachfolgenden Lesevorgang statt, sie garantieren jedoch keine Atomizität. Wenn beispielsweise die Zählvariable mit volatile geändert wird, ist die count++-Operation nicht atomar. Die von der AtomicInteger-Klasse bereitgestellte atomare Methode kann diese Operation atomar machen. Die Methode getAndIncrement() führt beispielsweise eine Inkrementierungsoperation aus, um eins zum aktuellen Wert hinzuzufügen. Ähnliche Operationen können auch für andere Datentypen und Referenzvariablen ausgeführt werden.

47) Was passiert, wenn ein Thread innerhalb eines synchronisierten Blocks eine Ausnahme auslöst?

Diese Frage hat viele Java-Programmierer beunruhigt. Wenn Ihnen der Hinweis einfällt, ob die Sperre aufgehoben wird, um sie zu beantworten, können Sie hoffen, sie richtig zu stellen. Unabhängig davon, ob Ihr synchronisierter Block normal oder abnormal beendet wird, gibt der Thread im Inneren die Sperre frei. Im Vergleich zur Sperrschnittstelle bevorzuge ich daher den synchronisierten Block, da ich zum Aufheben der Sperre keine Energie aufwenden muss durch Aufheben der Sperre im „finally“-Block.

48) Was ist die Doppelprüfsperre im Singleton-Modus?

Diese Frage wird oft in Java-Interviews gestellt, aber Interviewer sind mit der Beantwortung dieser Frage nur zu 50 % zufrieden. Die Hälfte der Leute kann kein Double-Check-Locking schreiben und die Hälfte der Leute kann die versteckten Gefahren nicht erklären und nicht erklären, wie Java 1.5 sie behebt. Es handelt sich tatsächlich um eine alte Methode zum Erstellen von Thread-sicheren Singletons. Beim ersten Erstellen der Singleton-Instanz wird versucht, eine einzelne Sperre zur Leistungsoptimierung zu verwenden. Dies schlägt jedoch in JDK1.4 fehl, da dies für mich persönlich zu komplex ist. Es gefällt mir auch nicht. Wie auch immer, selbst wenn es Ihnen nicht gefällt, lohnt es sich, es zu wissen, weil es oft gefragt wird.

49) Wie erstelle ich einen threadsicheren Singleton in Java?

Dies ist eine Fortsetzung der obigen Frage. Wenn Sie doppelt überprüfte Sperren nicht mögen und der Interviewer nach Alternativen zum Erstellen einer Singleton-Klasse fragt, können Sie das Klassenladen und der JVM verwenden B. statische Variableninitialisierungsfunktionen zum Erstellen von Singleton-Instanzen oder die Verwendung von Aufzählungstypen zum Erstellen von Singletons, diese Methode gefällt mir.

50) Schreiben Sie 3 Multithreading-Best Practices, denen Sie folgen

Diese Art von Frage gefällt mir am besten. Ich glaube, Sie schreiben gleichzeitigen Code, um die Leistung zu verbessern. Bestimmt am besten Praktiken werden ebenfalls befolgt. Hier sind drei Best Practices, die meiner Meinung nach die meisten Java-Programmierer befolgen sollten:

  • Geben Sie Ihren Threads einen aussagekräftigen Namen.
    Dies macht es einfacher, Fehler zu finden oder zu verfolgen. OrderProcessor, QuoteProcessor oder TradeProcessor sind viel bessere Namen als Thread-1 und Thread-3. Geben Sie dem Thread einen Namen, der sich auf die Aufgabe bezieht, die er ausführen möchte. Alle wichtigen Frameworks und sogar JDK folgen dieser Best Practice.
  • Vermeiden Sie Sperren und reduzieren Sie den Umfang der Synchronisierung.
    Sperren sind teuer und der Kontextwechsel nimmt mehr Zeit und Platz in Anspruch. Versuchen Sie, die Synchronisierung und Sperren auf ein Minimum zu beschränken, um den kritischen Abschnitt zu reduzieren. Daher bevorzuge ich synchronisierte Blöcke gegenüber synchronisierten Methoden, da ich dadurch die absolute Kontrolle über die Sperre habe.
  • Verwenden Sie mehr Synchronisationsklassen und weniger den Einsatz von Warten und Benachrichtigen
    Zuallererst vereinfachen Synchronisationsklassen wie CountDownLatch, Semaphore, CyclicBarrier und Exchanger Codierungsvorgänge, während es schwierig ist, den komplexen Kontrollfluss mithilfe von Warten zu steuern und benachrichtigen. Zweitens werden diese Klassen von den besten Unternehmen geschrieben und gepflegt. Sie werden in nachfolgenden JDKs kontinuierlich optimiert und verbessert. Mit diesen übergeordneten Synchronisierungstools kann Ihr Programm mühelos optimiert werden.
  • Verwenden Sie mehr gleichzeitige Sammlungen und weniger synchronisierte Sammlungen
    Dies ist eine weitere bewährte Methode, die einfach zu befolgen ist und enorme Vorteile bietet. Sie sind skalierbarer als synchronisierte Sammlungen. Verwenden Sie daher gleichzeitige Sammlungen, wenn Sie gleichzeitig programmieren Wirkung ist besser. Wenn Sie das nächste Mal Map verwenden müssen, sollten Sie zunächst über die Verwendung von ConcurrentHashMap nachdenken.

51) Wie erzwinge ich das Starten eines Threads?

Bei dieser Frage geht es darum, wie man die Java-Garbage Collection erzwingt. Es gibt derzeit keine Methode, um die Garbage Collection durchzuführen, es gibt jedoch keine Erfolgsgarantie. Es gibt keine Möglichkeit, den Start eines Threads in Java zu erzwingen, er wird vom Thread-Scheduler gesteuert und Java veröffentlicht die entsprechende API nicht.

52) Was ist das Fork-Join-Framework in Java?

Das Fork-Join-Framework ist ein effizientes Tool, das in JDK7 erschien und mit dem Java-Entwickler die Vorteile von Multiprozessoren auf modernen Servern voll ausnutzen können. Es wurde speziell für Anwendungen entwickelt, die rekursiv in viele Untermodule unterteilt werden können, mit dem Ziel, die gesamte verfügbare Rechenleistung zu nutzen, um die Programmleistung zu verbessern. Ein großer Vorteil des Fork-Join-Frameworks besteht darin, dass es einen arbeitsraubenden Algorithmus verwendet, der mehr Aufgaben erledigen und Aufgaben von anderen Threads zur Ausführung stehlen kann.

53) Was ist der Unterschied zwischen dem Aufruf der Methoden „wait()“ und „sleep()“ im Java-Multithreading?

Sowohl das Warten als auch das Ruhen führen in Java-Programmen zu einer Art Pause und können unterschiedliche Anforderungen erfüllen. Die Methode „wait()“ wird für die Kommunikation zwischen Threads verwendet. Wenn die Wartebedingung wahr ist und andere Threads aktiviert werden, wird die Sperre aufgehoben, während die Methode „sleep()“ nur CPU-Ressourcen freigibt oder den aktuellen Thread für einen Zeitraum von anhält Zeit, hebt die Sperre jedoch nicht auf.

Weitere Kenntnisse zu Java-Interviews finden Sie in der Rubrik Java-Interviewfragen!

Das obige ist der detaillierte Inhalt vonFragen zum Java-Multithreading-Interview, die es wert sind, gesammelt zu werden (mit Antworten). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen