1. Synchronisierte und reentrantlock-Ähnlichkeiten und -Unterschiede
Gleichheit
Beide implementieren Multithread-Synchronisation und Speichersichtbarkeitssemantik, und beide sind wiedereintrittsfähige Sperren
Unterschied
Der Implementierungsmechanismus ist unterschiedlich und wird durch Java-Objekt-Head-Lock-Markierung und Monitor synchronisiert Das Objekt implementiert Reentrantlock und synchronisiert über CAS, ASQ (AbstractQueuedSynchronizer) und Locksupport (zum Blockieren und Entsperren). Es basiert auf dem JVM-Speichermodell, um die Sichtbarkeit von Multithread-Speicher mit gemeinsam genutzten Variablen sicherzustellen Gemeinsam genutzte Variablen können über den flüchtigen Status von ASQ auf unterschiedliche Weise synchronisiert werden. Sie können Instanzmethoden (Sperrinstanzobjekte), statische Methoden (Sperrklassenobjekte) und Codeblöcke (angegebene Sperrobjekte anzeigen) ändern trylock()/lock() Methode, die Sperre muss im „finally“-Block aufgehoben werden. Der Umfang der Funktionen variiert.
bietet eine umfassende Semantik, wie z ), unterbrechbare Sperre (lockInterruptously), Bedingung (Bereitstellung von Wait-, Signal- und anderen Methoden). 🎜>2. Warum liest ConcurrentHashmap ohne Sperre
jdk1.71) Der Schlüssel, der Hash und der nächste in HashEntry sind alle endgültig und nur der Header kann eingefügt werden oder gelöscht.
2) Das Wertfeld der HashEntry-Klasse wird als flüchtig deklariert3) Es ist nicht erlaubt, Null als Schlüssel und Wert zu verwenden Wenn das Wertfeld eines HashEntry null ist, weiß es, dass ein Konflikt aufgetreten ist – ein Neuordnungsphänomen ist aufgetreten (Put legt ein neues Wertobjekt fest. Neuordnung der Bytecode-Anweisungen), Sie müssen diesen Wert sperren und erneut lesen 4) Die Anzahl der flüchtigen Variablen koordiniert die Speichersichtbarkeit zwischen Lese- und Schreibthreads und liest die Anzahl der Leseoperationen zuerst. Die geänderte Leseoperation der Schreiboperation kann gemäß dem Vorher-Transitivitätsprinzip gesehen werden jdk1.81) Node's val und next sind beide flüchtig 2) Die unsicheren Operationen entsprechend tabAt und casTabAt implementieren flüchtige Semantik3. Die Rolle von ContextClassLoader (Thread-Kontext-Klassenlader)
überschreibt den übergeordneten Klassenlader-Delegationsmechanismus zum Laden von Klassen, z. B. die Serviceloader-Implementierung, und verwendet den Thread-Kontext-Klassenlader zum Laden von Klassen um sicherzustellen, dass der Klassenlader zwischen mehreren Threads, die kommunizieren müssen, derselbe sein sollte, um Typkonvertierungsausnahmen (ClassCastException) zu verhindern, die durch unterschiedliche Klassenlader verursacht werden)Tomcat-Klassenlademechanismus
Verschiedene Anwendungen verwenden unterschiedliche Webapp-Klassenlader, um den Effekt der Anwendungsisolation zu erzielen. Unterhalb des Webapp-Klassenladers können die von verschiedenen Anwendungen gemeinsam genutzten JSP-Klassenlader im Verzeichnis „Shared Class Loader/Shared“ abgelegt werden5. Osgi-Klassenlademechanismus
OSGI-Klassenlademodell ist Mesh Ja, Sie können sich gegenseitig zwischen Modulen delegieren (Bundle)osgi The Der Schlüssel zur Realisierung einer modularen Hot-Bereitstellung ist die Implementierung des benutzerdefinierten Klassenladers. Jedes Bundle verfügt über einen eigenen Klassenlader, der ersetzt werden kann, wenn ein Bundle geladen werden muss Hot-Ersetzung des Codes erreichen
Beim Empfang einer Klassenladeanfrage führt osgi eine Klassensuche in der folgenden Reihenfolge durch: 1) Delegieren Sie Klassen, die mit java.* beginnen, an den übergeordneten Klassenlader zum Laden 2) Andernfalls delegieren Sie Klassen in der Delegationsliste (definiert in der Konfigurationsdatei org.osgi.framework.bootdelegation) an den übergeordneten Klassenlader. Laden 3) Andernfalls prüfen Sie, ob Es wird im Import-Paket deklariert. Wenn ja, wird der Klassenlader des zum Exportieren dieser Klasse delegierten Pakets geladen. 4) Andernfalls prüfen Sie, ob es im Require-Bundle deklariert ist. Wenn ja, delegieren Sie das Klassenladeanforderung an den Klassenlader des erforderlichen Bundles 5) Andernfalls suchen Sie den ClassPath des aktuellen Bundles und verwenden Sie Ihren eigenen Klassenlader, um ihn zu laden6) Andernfalls prüfen Sie, ob Wenn ja, delegieren Sie sie zum Laden an den Klassenlader des Fragment-Bundles. 7) Suchen Sie andernfalls nach dem Dynamic Import-Paket (Dynamic Import ist nur im Bundle verfügbar). wird nur geladen, wenn dieses Paket tatsächlich verwendet wird) und wird zum Laden an den Klassenlader des entsprechenden Bundles delegiert8) Andernfalls schlägt die Klassensuche fehl
6 end a Der laufende Thread
verwendet das Exit-Flag. Diese Flagvariable muss für mehrere Threads sichtbar sein.verwendet Interrupt, kombiniert mit isInterrupted(), um
7. Threadlocal-Nutzungsszenarien und -ProblemeThreadlocal kann das Problem von Multi-Thread-Shared-Variablen nicht lösen, ohne dass es zu Störungen in verschiedenen Threads kommt einander
Wird zum Speichern von Thread-Kontextvariablen verwendet, um das mehrfache Lesen von Variablen durch denselben Thread zu erleichtern, z. B. Transaktionen und Datenbankverbindungsverbindungen. Wird eher in der Webprogrammierung verwendetFrage: Beachten Sie das Thread Local wird in Thread-Pool-Szenarien verwendet. Da der tatsächliche Variablenwert in der Threadlocalmap-Typvariablen des Threads gespeichert wird, kann der vorherige alte Wert erhalten werden, wenn der Wert nicht zuerst entfernt oder festgelegt wird
Problem: Achten Sie auf den Speicherverlust im Thread-Pool-Szenario. Obwohl das Abrufen/Setzen von Threadlocal den Eintrag mit Schlüssel löscht (Schlüssel ist eine schwache Referenz von Threadlocal, Wert ist eine starke Referenz, was dazu führt, dass der Wert dies nicht tut freigegeben werden), aber es ist am besten, es zu entfernen
Der Prozess des Thread-Pools vom Start bis zur Arbeit
Beim ersten Erstellen gibt es keine Thread darin, umexecute() aufzurufen. Beim Hinzufügen einer Aufgabe:
1) Wenn die Anzahl der laufenden Threads kleiner als der Kernparameter corePoolSize ist, erstellen Sie weiterhin Threads, um diese Aufgabe auszuführen
2) Andernfalls, wenn die Anzahl der laufenden Threads größer oder gleich corePoolSize ist, fügen Sie die Aufgabe zur Blockierungswarteschlange hinzu
3) Andernfalls, wenn die Warteschlange voll ist und die Anzahl der gleichzeitig ausgeführten Threads zunimmt kleiner als der Kernparameter „maximumPoolSize“ ist, erstellen Sie weiterhin Threads, um diese Aufgabe auszuführen
4) Andernfalls wird die Verarbeitung durchgeführt, wenn die Warteschlange voll ist und die Anzahl der gleichzeitig ausgeführten Threads größer oder gleich „maximumPoolSize“ ist gemäß der festgelegten Ablehnungsrichtlinie
5) Eine Aufgabe abschließen und mit der Verarbeitung der nächsten Aufgabe fortfahren
6) Wenn weiterhin keine Aufgabe verarbeitet wird, wird der Thread unterbrochen oder der Thread-Pool geschlossen , der Thread beendet die Ausführung.
7) Andernfalls ermitteln Sie, ob die Anzahl der im Thread-Pool ausgeführten Threads größer ist als die Anzahl der Kern-Threads Thread endet, sonst blockiert der Thread. Nachdem alle Thread-Pool-Aufgaben ausgeführt wurden, beträgt die verbleibende Thread-Pool-Größe corePoolSize
9 Der Unterschied zwischen BlockingQueue Take und Poll
Poll(time) : take Nehmen Sie das Objekt an erster Stelle in der BlockingQueue. Wenn es nicht sofort entfernt werden kann, können Sie die durch den Zeitparameter angegebene Zeit abwarten. Wenn es nicht abgerufen werden kann, wird null zurückgegeben
take(). : Nehmen Sie das Objekt an erster Stelle in der BlockingQueue. Wenn die BlockingQueue leer ist, wird blockiert, bis ein neues Objekt zur BlockingQueue hinzugefügt wird
10 So erhalten Sie das Ergebnis von FutureTask ohne Blockierung
get(long timeout, TimeUnit unit), timeout Kehren Sie dann zur
-Abfrage zurück, beurteilen Sie zunächst mit isDone(), ob der Vorgang abgeschlossen ist, und rufen Sie dann get()
11. Blockierungswarteschlange: Was sollte passieren, wenn das System ausfällt? Die Verarbeitung der Warteschlange muss auf der Festplatte gespeichert werden wird erst zurückgegeben, wenn die Persistenz erfolgreich ist. Der Verbraucherthread lädt die Daten von der Festplatte in die Speicherblockierungswarteschlange und behält den Verbrauchsoffset bei. Beim Start werden Daten von der Festplatte geladen und entsprechend dem Verbrauchsoffset zur Nachrichtenwarteschlange hinzugefügt Stellen Sie sicher, dass Nachrichten nicht verloren gehen, Sequenznummern generiert werden, der Verbrauch idempotent ist und der Produktionsstatus nach dem Neustart des Systems basierend auf dem Verbrauchsprozess bestimmt wird
12. NIO und Der Unterschied zwischen herkömmlicher E/ASpeichern von Threads, NIO-Änderungen von jedem Thread, die das Lesen und Schreiben in einen einzelnen Thread (d. h. Selector) blockieren müssen, der für die Verarbeitung mehrerer Kanalregistrierungen (register) verantwortlich ist. Sammlung von Interessenereignissen (SelectionKey) (unten). Die Schicht basiert auf epoll(), das vom Betriebssystem bereitgestellt wird. Netty Bossgroup kümmert sich um das Akzeptieren von Verbindungen, Workergroup kümmert sich um bestimmte Geschäftsprozesse und das Lesen und Schreiben von Daten. NIO stellt nicht blockierende Vorgänge bereit. Herkömmliche E/A verarbeitet Daten auf Streaming-Art und NIO NIO stellt einen Bytepuffer bereit, der in In-Heap- und Off-Heap-Puffer unterteilt ist. Beim Lesen und Schreiben werden sie zuerst in diesem Puffer abgelegt, und der Kernel überträgt sie dann über den Kanal an das andere Ende Off-Heap-Puffer wird nicht entfernt, verbesserte Leistung
13. Wiederholbare Zeichenfolgen werden in der Liste gespeichert, wie man eine Zeichenfolge löschtIteratorbezogene Methoden aufrufen Löschung löschen und durch Löschung verursachte positive Sequenz-Array-Neuanordnung verhindern, Problem mit dem Überspringen von Array-Elementen im Index
14. Was sind die GC-WURZELN (relevanter für die tägliche Entwicklung sind damit verbundene Speicherlecks)Die derzeit aktiven Stack-Frames aller Java-Threads verweisen auf Verweise auf Objekte im GC-Heap, sodass nicht verwendete Objekte rechtzeitig auf Null gesetzt werden, um die Speicherrecycling-Effizienz zu verbessern. Objekte, auf die durch statische Variablen verwiesen wird Statische Variablen werden reduziert, insbesondere die Größe statischer Sammlungsvariablen. Die in der Sammlung gespeicherten Objekte überschreiben euqls() und hashcode(), um ein kontinuierliches Wachstum zu verhindern
Objekte, auf die von der lokalen Methode JNI verwiesen wird
Konstante Referenzen im Methodenbereich Object, wodurch die Notwendigkeit reduziert wird, String.intern() für lange Zeichenfolgen aufzurufen
Klassenobjekte, die vom Klassenlader geladen werden. Wenn der benutzerdefinierte Klassenlader ungültig ist, setzen Sie ihn rechtzeitig auf Null und achten Sie auf die Isolation zwischen den vom Klassenlader in JVM geladenen Objekten Einige statische Datenstrukturen verweisen auf Verweise auf Objekte im GC-Heap
Das obige ist der detaillierte Inhalt von14 häufig gestellte Fragen im Internet-Java-Interview. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!