Dieser Artikel vermittelt Ihnen relevantes Wissen über Java, das hauptsächlich verwandte Fragen zu Thread-Interviewfragen organisiert, einschließlich des Unterschieds zwischen synchronisierten modifizierten gewöhnlichen Methoden und statischen Methoden, dem Prinzip der CAS-sperrenfreien Programmierung, Volatilität und Synchronisierung. Was sind die Unterschiede? und so weiter? Werfen wir einen Blick darauf. Ich hoffe, es wird für alle hilfreich sein.
Empfohlene Studie: „Java-Video-Tutorial“
Objektsperren werden für Objektinstanzmethoden oder eine Objektinstanz verwendet, und Klassensperren werden für statische Methoden einer Klasse oder Klassenobjekte einer Klasse verwendet. Wir wissen, dass es viele Objektinstanzen einer Klasse geben kann, jede Klasse jedoch nur ein Klassenobjekt hat, sodass sich die Objektsperren verschiedener Objektinstanzen nicht gegenseitig stören, es jedoch nur eine Klassensperre für jede Klasse gibt.
Eine Sache, die beachtet werden muss, ist, dass die Klassensperre tatsächlich nur eine konzeptionelle Sache ist und nicht tatsächlich existiert. Die Klassensperre sperrt tatsächlich das entsprechende Klassenobjekt jeder Klasse. Klassensperren und Objektsperren stören sich auch nicht gegenseitig.
Sichtbarkeit bedeutet, dass, wenn mehrere Threads auf dieselbe Variable zugreifen und ein Thread den Wert der Variablen ändert, andere Threads den geänderten Wert sofort sehen können.
Da alle Operationen an Variablen durch Threads im Arbeitsspeicher ausgeführt werden müssen und Variablen im Hauptspeicher nicht direkt gelesen und geschrieben werden können, befinden sich die gemeinsam genutzten Variablen V zunächst in ihrem eigenen Arbeitsspeicher und werden dann mit dem Hauptspeicher synchronisiert. Allerdings wird es nicht rechtzeitig in den Hauptspeicher geleert, sondern es entsteht ein gewisser Zeitunterschied. Offensichtlich ist die Operation von Thread A an der Variablen V zu diesem Zeitpunkt für Thread B nicht mehr sichtbar.
Um das Problem der Sichtbarkeit gemeinsamer Objekte zu lösen, können wir das Schlüsselwort volatile oder lock verwenden.
Aktuelle Prozessoren unterstützen grundsätzlich die CAS()-Anweisung, aber die von jedem Hersteller implementierten Algorithmen sind unterschiedlich. Jeder CAS-Operationsprozess enthält drei Operatoren: eine Speicheradresse V, einen erwarteten Wert A und einen neuen Wert B. Während des Betriebs, wenn Wenn der an dieser Adresse gespeicherte Wert gleich dem erwarteten Wert A ist, wird der Wert an der Adresse dem neuen Wert B zugewiesen, andernfalls wird keine Operation ausgeführt.
Die Grundidee von CAS besteht darin, dass, wenn der Wert an dieser Adresse dem erwarteten Wert entspricht, ihr ein neuer Wert zugewiesen wird. Andernfalls wird nichts anderes getan, als den ursprünglichen Wert zurückzugeben. Loop CAS besteht darin, Cas-Operationen kontinuierlich in einer Schleife auszuführen, bis sie erfolgreich sind. Wir können auch über drei große Probleme mit CAS sprechen.
Ein Thread kann wiederholt jeden Codeblock betreten, der mit einer Sperre synchronisiert ist, die er bereits besitzt. Synchronized und ReentrantLock sind beide Wiedereintrittssperren. Was die Implementierung angeht, bestimmt er jedes Mal, wenn er eine Sperre erhält, ob der Thread, der die Sperre erhält, er selbst ist, und akkumuliert einfach den Zähler. Jedes Mal, wenn die Sperre aufgehoben wird, wird der Zähler dekrementiert, bis der Rechner auf Null zurückkehrt, was dies anzeigt Der Thread wurde komplett freigegeben. Die unterste Ebene wird mithilfe von AQS in JUC implementiert.
Es handelt sich um das Grundgerüst, das zum Erstellen von Sperren oder anderen Synchronisierungskomponenten verwendet wird. Beispielsweise werden ReentrantLock, ReentrantReadWriteLock und CountDownLatch auf Basis von AQS implementiert. Es verwendet eine int-Mitgliedsvariable, um den Synchronisationsstatus darzustellen, und schließt die Warteschlangenarbeit von Ressourcenerfassungsthreads über die integrierte FIFO-Warteschlange ab. Es handelt sich um eine Variantenimplementierung der CLH-Warteschlangensperre. Es können zwei Synchronisierungsmethoden erreicht werden: exklusiv und gemeinsam genutzt.
Die Hauptmethode zur Verwendung von AQS ist die Vererbung. Unterklassen erben AQS und implementieren ihre abstrakten Methoden, um den Synchronisierungsstatus zu verwalten. Das Design des Synchronisierers basiert auf dem Vorlagenmethodenmuster. Wenn wir also unsere eigene Synchronisierungstoolklasse implementieren möchten um mehrere davon abzudecken, z. B. tryAcquire, tryReleaseShared usw.
Der Zweck dieses Designs besteht darin, dass Synchronisierungskomponenten (z. B. Sperren) benutzerorientiert sind. Es definiert die Schnittstelle, über die Benutzer mit Synchronisierungskomponenten interagieren können (z. B. um zwei Threads den parallelen Zugriff zu ermöglichen) und die Implementierungsdetails zu verbergen ist für den Implementierer von Sperren, der die Implementierung von Sperren vereinfacht und zugrunde liegende Vorgänge wie Synchronisationsstatusverwaltung, Thread-Warteschlangen, Warten und Aufwachen abschirmt. Dadurch werden die Bereiche effektiv isoliert, auf die sich Benutzer und Implementierer konzentrieren müssen.
Intern verwaltet AQS einen gemeinsamen Ressourcenstatus und verwendet den integrierten FIFO, um die Warteschlangenarbeit der Ressourcenbeschaffungsthreads abzuschließen. Die Warteschlange besteht nacheinander aus Knotenknoten. Jeder Knotenknoten verwaltet eine vorherige Referenz und eine nächste Referenz, die auf seinen eigenen Vorgänger- bzw. Nachfolgerknoten verweisen und eine doppelt verknüpfte Liste mit zwei Enden bilden.
Synchronisiertes (dieses) Prinzip: Beinhaltet zwei Anweisungen: Monitorenter, Monitorexit. Ausgehend von den Dekompilierungsergebnissen der Synchronisierungsmethode wird die Synchronisierung der Methode nicht durch die Anweisungen Monitorenter und Monitorexit erreicht Bei der gewöhnlichen Methode gibt es einen zusätzlichen ACC_SYNCHRONIZED-Bezeichner im Konstantenpool.
Die JVM implementiert die Methodensynchronisierung basierend auf dieser Kennung: Wenn die Methode aufgerufen wird, prüft die aufrufende Anweisung, ob das Zugriffsflag ACC_SYNCHRONIZED der Methode gesetzt ist. Wenn es gesetzt ist, ruft der Ausführungsthread zuerst den Monitor ab und führt ihn dann aus Nachdem die Methode erfolgreich erfasst wurde, wird der Monitor freigegeben, nachdem die Methode ausgeführt wurde. Während der Ausführung der Methode kann kein anderer Thread dasselbe Monitorobjekt erneut abrufen.
Einführung von Technologien wie Spin-Lock, adaptivem Spin-Lock, Lock-Eliminierung, Lock-Coarsing, Bias-Lock, Lightweight-Lock, Escape-Analyse und anderen Technologien, um die Kosten von Lock-Operationen zu senken.
Objektsperren werden für Objektinstanzmethoden oder eine Objektinstanz verwendet, und Klassensperren werden für statische Methoden einer Klasse oder Klassenobjekte einer Klasse verwendet. Wir wissen, dass es viele Objektinstanzen einer Klasse geben kann, jede Klasse jedoch nur ein Klassenobjekt hat, sodass sich die Objektsperren verschiedener Objektinstanzen nicht gegenseitig stören, es jedoch nur eine Klassensperre für jede Klasse gibt.
Eine Sache, die beachtet werden muss, ist, dass die Klassensperre tatsächlich nur eine konzeptionelle Sache ist und nicht tatsächlich existiert. Die Klassensperre sperrt tatsächlich das entsprechende Klassenobjekt jeder Klasse. Klassensperren und Objektsperren stören sich auch nicht gegenseitig.
Es gibt keine Garantie für die Rolle von DCL: Volatilität stellt die Sichtbarkeit und Ordnung geänderter Variablen sicher und stellt sicher, dass im Singleton-Modus die Ausführungsreihenfolge beim Erstellen eines Objekts
sein muss Volatile ist der einfachste Synchronisationsmechanismus. Volatile garantiert die Sichtbarkeit, wenn verschiedene Threads mit dieser Variablen arbeiten, d. h. wenn ein Thread den Wert einer Variablen ändert, ist der neue Wert sofort für andere Threads sichtbar. Volatile kann jedoch die Atomizität von Vorgängen nicht garantieren, sodass zusammengesetzte Schreibvorgänge unter Multithreads zu Thread-Sicherheitsproblemen führen.
Das Schlüsselwort synchronisiert kann zum Ändern von Methoden oder in Form von synchronisierten Blöcken verwendet werden. Es stellt hauptsächlich sicher, dass mehrere Threads gleichzeitig nur einen Thread in einer Methode oder einem synchronisierten Block haben können. und Exklusivität, auch bekannt als integrierte Schließmechanismen.
Der Daemon-Thread ist ein Support-Thread, da er hauptsächlich für die Hintergrundplanung und Support-Arbeit im Programm verwendet wird. Dies bedeutet, dass die Java Virtual Machine beendet wird, wenn in einer Java Virtual Machine keine Nicht-Daemon-Threads vorhanden sind. Ein Thread kann als Daemon-Thread festgelegt werden, indem Thread.setDaemon(true) aufgerufen wird. Wir verwenden es im Allgemeinen nicht. Der Garbage-Collection-Thread ist beispielsweise der Daemon-Thread.
Thread-Unterbrechung : Entweder ist die Ausführung des Laufs abgeschlossen oder es wird eine nicht behandelte Ausnahme ausgelöst, die dazu führt, dass der Thread vorzeitig beendet wird. Die dem Thread-Thread entsprechenden APIs zum Anhalten, Fortsetzen und Stoppen von Vorgängen sind suspend(), resume() und stop(). Diese APIs sind jedoch veraltet und werden nicht zur Verwendung empfohlen. Weil es dazu führt, dass das Programm in einem unsicheren Zustand arbeitet. Die Aussetzung der Sicherheit besteht darin, dass andere Threads den Interrupt-Vorgang unterbrechen, indem sie die Methode interrupt () eines Threads A aufrufen, und der unterbrochene Thread bestimmt, ob er durch den Thread unterbrochen wird, indem er die Methode Thread.interrupted( verwendet. ) wird verwendet, um zu bestimmen, ob der aktuelle Thread unterbrochen ist, aber Thread.interrupted() schreibt auch das Interrupt-Flag-Bit auf false um.
Nach dem Aufruf von yield() und sleep() wird die vom aktuellen Thread gehaltene Sperre nicht aufgehoben.
Nach dem Aufruf der Methode wait () wird die vom aktuellen Thread gehaltene Sperre aufgehoben, und nachdem der aktuelle Thread aktiviert wurde, konkurriert er erneut um die Sperre. Der Code hinter der Methode wait wird erst ausgeführt, nachdem die Sperre aktiviert wurde konkurrierte.
Warten wird normalerweise für die Interaktion zwischen Threads verwendet, Ruhe wird normalerweise verwendet, um die Ausführung anzuhalten, und die Methode yield() bewirkt, dass der aktuelle Thread den CPU-Besitz aufgibt.
Der Wartethread verwendet notify/notifyAll() zum Aufwachen.
ThreadLocal ist eine spezielle Variable in Java. ThreadLocal stellt für jeden Thread eine Kopie der Variablen bereit, sodass nicht jeder Thread zu einem bestimmten Zeitpunkt auf dasselbe Objekt zugreift, wodurch die Datenfreigabe durch mehrere Threads isoliert wird.
In Bezug auf die interne Implementierung verfügt jeder Thread über eine ThreadLocalMap, die zum Speichern einer Kopie der Variablen verwendet wird, die jedem Thread gehören.
Während des Entwicklungsprozesses kann der rationelle Einsatz von Thread-Pools drei Vorteile bringen.
Erstens: Reduzieren Sie den Ressourcenverbrauch.
Zweitens: Reaktionsgeschwindigkeit verbessern.
Drittens: Verbessern Sie die Thread-Verwaltbarkeit.
Es kann mit der Join-Methode implementiert werden.
Empfohlenes Lernen: „Java-Video-Tutorial“
Das obige ist der detaillierte Inhalt vonFassen Sie Fragen zu Java-Thread-Interviews zusammen und organisieren Sie sie. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!