Was ist Java multithreading
Java bietet einen Mechanismus zum Umgang mit mehreren Aufgaben gleichzeitig (gleichzeitig und unabhängig). Mehrere Threads koexistieren im selben JVM -Prozess, sodass sie den gleichen Speicherplatz teilen. Im Vergleich zu mehreren Prozessen ist die Kommunikation zwischen mehreren Threads leichter. Nach meinem Verständnis soll Java Multithreading ausschließlich die CPU -Nutzung verbessern. Java -Threads haben 4 Staaten: neu, laufbar, blockiert und tot. Der Schlüssel blockiert. Blockieren bedeutet zu warten. Der blockierende Thread beteiligt sich nicht an der Zeitschichtzuweisung des Thread -Dispatcher, sodass die CPU natürlich nicht verwendet wird. In einer multitHhread-Umgebung laufen diese nicht blockierten Threads aus und nutzen die CPU voll aus.
Eine Zusammenfassung von 40 Fragen
1. Was nutzt das Multi-Threading?
Eine Frage, die vielen Menschen Unsinn erscheinen mag: Ich kann einfach Multi-Threading verwenden, aber wie nützt es? Meiner Meinung nach ist diese Antwort noch mehr Unsinn. Das sogenannte "Wissen, was wahr ist" ist "zu wissen, was wahr ist", "zu wissen, was wahr ist", "Warum benutze" zu wissen, was wahr ist. Nur wenn man das Maß an "Wissen, was wahr ist", kann man gesagt werden, dass man einen Wissenspunkt frei anwenden kann. Ok, lassen Sie mich Ihnen sagen, was ich über dieses Problem denke:
(1) Geben Sie den Vorteilen der Multi-Core-CPU das volle Spiel
Mit der Weiterentwicklung der Industrie sind die heutigen Laptops, Desktops und sogar kommerziellen Anwendungsserver alle Dual-Core, und 4-Core, 8-Core oder sogar 16-Core sind keine Seltenheit. Wenn es sich um ein einsthreades Programm handelt, werden 50% auf der Dual-Core-CPU und 75% auf der 4-Core-CPU verschwendet. Das sogenannte "Multi-Threading" auf einer Einzelkern-CPU ist gefälschter Multi-Threading. Der Prozessor verarbeitet nur ein Stück Logik gleichzeitig, aber die Threads wechseln relativ schnell, was so aussieht, als würden mehrere Threads "gleichzeitig" ausgeführt. Multithreading bei Multi-Core-CPUs ist das echte Multithreading. Es kann Ihre Mehrsegmentlogik gleichzeitig und Multi-Threading ermöglichen. Es kann den Vorteilen von Multi-Core-CPUs wirklich volles Spiel geben, um das Ziel zu erreichen, die CPU voll auszunutzen.
(2) Verstopfung verhindern
Aus der Sicht der Effizienz des Programmbetriebs wird eine Einzelkern-CPU nicht nur den Vorteilen des Multi-Threading-Spiels nicht vollständig spielen, sondern auch die Gesamteffizienz des Programms verringern, da das Ausführen von Multi-Threading-Multi-Threading-CPU auf einer Einzelkern-CPU den Thread-Kontext-Umschalter verursacht, was die Gesamtwirkungsgrad des Programms verringert. Wir müssen jedoch noch Multithreading auf Einzelkern-CPUs anwenden, um eine Blockierung zu verhindern. Stellen Sie sich vor, eine einzelne CPU verwendet einen einzelnen Thread, solange der Thread blockiert ist, beispielsweise das Lesen bestimmter Daten aus der Ferne, hat der Peer lange nicht zurückgegeben und hat keine Zeitüberschreitungszeit festgelegt. Ihr gesamtes Programm wird nicht mehr ausgeführt, bevor die Daten zurückgegeben werden. Multi-Threading kann dieses Problem verhindern. Mehrere Threads werden gleichzeitig ausgeführt. Auch wenn der Code eines Threads aus dem Lesen von Daten blockiert ist, wirkt sich dies nicht auf die Ausführung anderer Aufgaben aus.
(3) leicht zu modellieren
Dies ist ein weiterer Vorteil, der nicht so offensichtlich ist. Angenommen, es gibt eine große Aufgabe A, ein einzelnes Thread-Programmieren, dann müssen Sie viel überlegen, und es ist problematischer, das gesamte Programmmodell zu erstellen. Wenn Sie diese große Aufgabe A jedoch in mehrere kleine Aufgaben, Aufgabe B, Aufgabe C und Aufgabe D, unterteilen, erstellen Sie ein Programmmodell separat und führen diese Aufgaben separat über mehrere Threads aus, es wird viel einfacher.
2. Erstellen Sie Threads
Ein häufigeres Problem ist im Allgemeinen zwei:
(1) Erben Sie die Thread -Klasse
(2) Implementieren Sie die Runnable -Schnittstelle
Was besser ist, ist es selbstverständlich, dass der letztere definitiv besser ist, da die Art und Weise, wie es Schnittstellen implementiert, flexibler ist als die Vererbungsklassenmethode und auch die Kopplung zwischen den Programmen reduzieren kann. Die interface-orientierte Programmierung ist auch der Kern der sechs Hauptprinzipien von Entwurfsmustern.
3. Die Differenz zwischen Start () -Methode und Run () -Methode
Nur wenn die Start () -Methode aufgerufen wird, werden die Eigenschaften des Multi-Threading angezeigt, und der Code in der Run () -Methode verschiedener Threads wird abwechselnd ausgeführt. Wenn Sie einfach die Run () -Methode aufrufen, wird der Code synchron ausgeführt. Sie müssen warten, bis der Code in der Run () -Methode eines Threads ausgeführt wird, bevor ein anderer Thread den Code in seiner Run () -Methode ausführen kann.
4. Der Unterschied zwischen Runnable -Schnittstelle und Callable -Schnittstelle
Es gibt eine tiefe Frage, und es zeigt auch die Breite des Wissens, das ein Java -Programmierer erlernt hat.
Der Rückgabewert der Run () -Methode in der Runnable -Schnittstelle ist ungültig, und es ist nur, den Code in der Run () -Methode auszuführen. Die CALL () -Methode in der Callable -Schnittstelle hat einen Rückgabewert, der ein generisches ist und verwendet werden kann, um die Ergebnisse der asynchronen Ausführung in Verbindung mit Future und Futuretask zu erhalten.
Dies ist eigentlich ein sehr nützliches Merkmal, da ein Hauptgrund, warum Multithreading schwieriger und komplexer ist als ein einzelnes Threading, ist, dass Multithreading voller Unbekannter ist. Wurde ein bestimmter Thread ausgeführt? Wie lange wird ein Thread schon ausgeführt? Sind die Daten, die wir erwarten, wenn ein Thread ausgeführt wird? Es ist nicht bekannt, dass wir nur darauf warten können, dass diese Multi-Thread-Aufgabe ausgeführt wird. Callable+Future/Futuretask kann die Ergebnisse des Multi-Thread-Laufens erhalten und die Aufgabe des Threads abbrechen, wenn die Wartezeit zu lang ist und die erforderlichen Daten nicht erhalten werden. Es ist wirklich nützlich.
5. Der Unterschied zwischen Cyclicbarrier und Countdownlatch
Beide Klassen, die ein bisschen ähnlich aussehen, können verwendet werden, um anzuzeigen, dass der Code an einem bestimmten Punkt unter java.util.concurrent ausgeführt wird. Der Unterschied zwischen den beiden ist:
(1) Nachdem ein Faden mit Cyclicbarrier an einem bestimmten Punkt ausgeführt wird, wird der Faden nicht mehr ausgeführt. Bis alle Threads diesen Punkt erreichen, werden alle Threads nicht wieder ausgeführt. Countdownlatch ist nicht. Nachdem ein Thread an einem bestimmten Punkt ausgeführt wird, gibt er nur einen bestimmten Wert -1, und der Thread wird weiter ausgeführt.
(2) CyclicBarrier kann nur eine Aufgabe ermitteln. Countdownlatch kann mehrere Aufgaben ermitteln
(3) CyclicBarrier kann wiederverwendet werden, Countdownlatch kann nicht wiederverwendet werden und der Zählwert wird 0 nicht wiederverwendet, und der Countdownlatch wird nicht erneut verwendet
6. Die Rolle von volatilen Schlüsselwörtern
Ein sehr wichtiges Thema ist, dass jeder Java-Programmierer, der Multi-Threading lernt und anwendet, ihn beherrschen muss. Die Voraussetzung, um die Rolle des flüchtigen Schlüsselworts zu verstehen, besteht darin, das Java -Speichermodell zu verstehen. Ich werde hier nicht über das Java -Speichermodell sprechen. Sie können sich auf Punkt 31 beziehen. Es gibt zwei Hauptfunktionen des volatilen Schlüsselworts:
(1) Multithreading dreht sich hauptsächlich um die beiden Merkmale der Sichtbarkeit und Atomizität. Die durch das volatile Schlüsselwort modifizierten Variablen stellen sicher, dass die Sichtbarkeit zwischen mehreren Threads, dh jedes Mal, wenn die volatile Variable gelesen wird, müssen die neuesten Daten sein.
(2) Die zugrunde liegende Codeausführung ist nicht so einfach wie die hochrangige Sprache, die wir sehen - Java -Programme. Die Ausführung ist Java -Code -> Bytecode -> Führen Sie den entsprechenden C/C ++ -Code gemäß dem Bytecode aus -> C/C ++ -Code wird in Montagesprachen kompiliert -> interagieren mit der Hardwareschaltung. Um eine bessere Leistung zu erzielen, kann die JVM die Anweisungen neu ordnen, und einige unerwartete Probleme können unter Multi-Threading auftreten. Die Verwendung von Volatile verbietet die semantische Neuordnung, was natürlich die Effizienz der Codeausführung in gewissem Maße verringert
Aus praktischer Sicht besteht eine wichtige Rolle von Flüchtigen darin, sich mit CAS zu verbinden, um die Atomizität zu gewährleisten. Weitere Informationen finden Sie in den Klassen unter dem Paket java.util.concurrent.atomic wie Atomicinder.
7. Was ist Fadensicherheit?
Eine weitere theoretische Frage, es gibt viele Antworten. Ich möchte einen geben, von dem ich persönlich die beste Erklärung für die beste Erklärung für den gleichen Ergebnis für Multithreading und Single-Threading gibt, dann ist Ihr Code mit Thread-Safe.
Dieses Problem ist etwas erwähnenswert, das heißt, es gibt mehrere Ebenen der Fadensicherheit:
(1) unveränderlich
Wie String, Ganzzahl, lang usw. sind sie alle letzte Typen. Kein Thread kann ihre Werte ändern. Wenn Sie sie ändern möchten, werden Sie keine neue erstellen. Daher können diese unveränderlichen Objekte ohne Synchronisationsmittel direkt in einer Umgebung mit mehreren Threaden verwendet werden.
(2) Absolute Fadensicherheit
Unabhängig von der Laufzeitumgebung benötigt der Anrufer keine zusätzlichen Synchronisationsmaßnahmen. Dazu müssen Sie normalerweise viele zusätzliche Kosten bezahlen. In Java sind es eigentlich keine Thread-Safe-Klassen. Es gibt jedoch auch Klassen, die absolut threadsicher sind, wie z.
(3) Relative Fadensicherheit
Relative Thread -Sicherheit nennen wir normalerweise die Sicherheit von Threads. Zum Beispiel sind Vektor-, Hinzufügen und Entfernen von Methoden atomare Operationen und werden nicht unterbrochen, ist jedoch darauf beschränkt. Wenn ein Faden, der einen bestimmten Vektor durchquert, gleichzeitig ein Faden hinzugefügt wird, tritt in 99% der Fälle eine ConcurrentModificationException auf, was der fehlgeschlagene Mechanismus ist.
(4) Fäden sind nicht sicher
Darüber gibt es nichts zu sagen. ArrayList, LinkedList, HashMap usw. sind alle nicht-Thread-Klassen.
8. So erhalten Sie Thread -Dump -Datei in Java
Bei Problemen wie Dead Loop, Deadlock, Blocking, langsamer Seitenöffnung usw. ist es der beste Weg, das Problem zu lösen. Der sogenannte Thread-Dump ist der Fadenstapel. Es gibt zwei Schritte, um den Fadenstapel zu erhalten:
(1) Holen Sie sich die PID des Threads, Sie können den JPS -Befehl verwenden, und Sie können auch PS -f | verwenden Grep Java in Linux -Umgebung
.
Außerdem bietet die Thread -Klasse eine GetStacktrace () -Methode, mit der auch der Thread -Stapel abgerufen werden kann. Dies ist eine Instanzmethode, daher ist diese Methode an eine bestimmte Threadinstanz gebunden. Jedes Mal, wenn Sie den Stack derzeit auf einem bestimmten Thread ausgeführt haben.
9. Was passiert, wenn ein Thread eine Laufzeitausnahme hat?
Wenn diese Ausnahme nicht erfasst wird, hört der Thread auf, auszuführen. Ein weiterer wichtiger Punkt ist: Wenn dieser Thread einen Monitor eines bestimmten Objekts enthält, wird der Objektmonitor sofort freigegeben
10. So teilen Sie Daten zwischen zwei Threads
Teilen Sie einfach Objekte zwischen Threads und rufen Sie dann auf und warten Sie warten/benachrichtigen/benachrichtigen, warten Sie/signalisieren/signalall. Zum Beispiel wurde das Blockieren der Warteschlangenblockierung zum Austausch von Daten zwischen Threads entwickelt.
11. Was ist der Unterschied zwischen Schlafmethode und Wait -Methode
Diese Frage wird häufig gestellt, sowohl die Schlafmethode als auch die Wartenmethode können verwendet werden, um die CPU für einen bestimmten Zeitraum aufzugeben. Der Unterschied besteht darin, dass die Schlafmethode den Monitor dieses Objekts nicht aufgibt, wenn der Thread den Überwachungsmodus enthält und die Warteverfahren den Monitor dieses Objekts aufgibt.
12. Welche Rolle spielt das Verbrauchermodell des Herstellers?
Diese Frage ist theoretisch, aber wichtig:
(1) Verbesserung der Betriebseffizienz des gesamten Systems, indem Sie die Produktionskapazität von Produzenten und Verbraucherverbrauchskapazitäten in Einklang bringen, was die wichtigste Rolle des Verbrauchermodells des Herstellers ist.
(2) Entkopplung ist dies die Funktion, die vom Hersteller- und Verbrauchermodell begleitet wird. Entkoppelung bedeutet, dass es weniger Verbindungen zwischen Produzenten und Verbrauchern gibt. Je weniger Verbindungen, desto mehr können sie sich selbst entwickeln, ohne gegenseitige Einschränkungen zu erhalten.
13. Was nützt ThreadLocal
Einfach ausgedrückt, ThreadLocal ist eine Praxis des Austauschs von Raum für Zeit. Jeder Thread behält eine ThreadLocal.ThreadLocalMap bei, die von der offenen Adressmethode implementiert ist, um die Daten zu isolieren und die Daten nicht weiterzugeben, sodass natürlich keine Fadensicherheitsprobleme vorhanden sind.
14. Warum warten () und benachrichtigen ()/Notifyall () -Methoden im Synchronisationsblock aufgerufen werden
Dies wird von JDK gezwungen. Die Methode Wait () und die Methode ()/NotifyAll () muss zuerst die Schloss des Objekts vor dem Aufrufen abrufen
15. Was ist der Unterschied zwischen Wait () Methode und melden ()/notifyall () Methode beim Abgeben des Objektmonitors
Der Unterschied zwischen der Wait () -Methode und der Methode "Notify ()/NotifyAll () beim Aufgeben des Objektmonitors besteht darin, dass die Wait () -Methode den Objektmonitor sofort freigibt, während die Methode von Benachrichtigung ()/NotifyAlL () auf den verbleibenden Code des Threads wartet, bevor der Objektmonitor ausgeführt wird.
16. Warum Thread Pool verwenden
Vermeiden Sie häufige Schöpfung und Zerstörung von Fäden, um die Wiederverwendung von Thread -Objekten zu erreichen. Darüber hinaus kann die Verwendung von Threadpools auch die Anzahl der Parallelität gemäß dem Projekt flexibel steuern.
17. So erkennen Sie, ob ein Thread einen Objektmonitor enthält
Ich habe auch eine Multithread -Interviewfrage im Internet gesehen, um zu wissen, dass es eine Möglichkeit gibt, zu bestimmen, ob ein Thread einen Objektmonitor enthält: Die Thread -Klasse bietet eine Holdslock (Object OBJ) -Methode, die nur dann true, wenn der Monitor des Objekts OBJ von einem Thread gehalten wird. Beachten Sie, dass dies eine statische Methode ist, was bedeutet, dass sich "ein bestimmter Thread" auf den aktuellen Thread bezieht.
18. Der Unterschied zwischen synchronisiertem und Wiedereintrittspreis
Synchronisiert ist das gleiche Schlüsselwort wie wäre es, sonst, für und während und wieder eingetragen, was eine Klasse ist, was der wesentliche Unterschied zwischen den beiden ist. Da Reentrantlock eine Klasse ist, bietet es immer flexiblere Funktionen als synchronisiert, die vererbt werden können, Methoden haben und verschiedene Klassenvariablen haben. Die Skalierbarkeit von Wiedereintritt als synchronisiert spiegelt sich in mehreren Punkten wider:
(1) Wiedereintrittskräfte kann die Wartezeit für den Erwerb des Schlosses festlegen und so Deadlock vermeiden
(2) Wiedereintrittslock kann verschiedene Sperrinformationen erhalten
(3) Wiedereintrittslock kann die Benachrichtigung über die Multi-Channel-Benachrichtigung flexibel implementieren
Darüber hinaus sind die Verriegelungsmechanismen der beiden tatsächlich unterschiedlich. Die zugrunde liegende Wiedereintrittsschloss ruft die Parkmethode von Unsicherheit auf, um zu sperren, und der synchronisierte Vorgang sollte das Markwort im Objektheader sein. Ich kann mir dessen nicht sicher sein.
19. Was ist die Parallelität der Concurrenthashmap
Die Parallelität von Concurrenthashmap ist die Größe des Segments, die standardmäßig 16 beträgt, was bedeutet, dass höchstens 16 Threads gleichzeitig eine gleichzeitige Funktionsweise betreiben können. Dies ist auch der größte Vorteil von Concurrenthashmap gegenüber Hashtable. Kann Hashtable in jedem Fall zwei Threads haben, die gleichzeitig die Daten in Hashtable erhalten?
20. Was ist ReadWriteLock
Lassen Sie uns zunächst deutlich machen, dass es nicht so ist, dass Reentrantlock nicht gut ist, es ist nur so, dass Reentrantlock manchmal begrenzt ist. Wenn neu eingetragen wird, kann es sein, dass Datenkonsistenzen durch Thread A -Schreibdaten und Thread -B -Lesen von Daten verhindern. Auf diese Weise ändert das Lesen von Daten jedoch die Daten nicht, wenn Thread C -Lesen und Thread D auch Daten lesen. Es ist nicht nötig, es zu sperren, aber es sperrt es trotzdem, was die Leistung des Programms verringert.
Aus diesem Grund wurde das Lese-schreiber-Sperre-ReadWriteLock geboren. ReadWriteLock ist eine Les-Schloss-Sperroberfläche. ReentranTreadWriteLock ist eine konkrete Implementierung der ReadWriteLock -Schnittstelle, die die Trennung von Lese- und Schreiben realisiert. Leseschlösser werden geteilt und Schreibschlösser sind exklusiv. Lesen und Lesen und Lesen werden sich nicht gegenseitig ausschließen. Nur lesen und schreiben, schreiben und lesen, schreiben und schreiben werden sich gegenseitig ausschließen und die Leistung von Lesen und Schreiben verbessern.
21. Was ist Futuretask
Dies wird tatsächlich früher erwähnt. Futuretask stellt eine asynchrone Betriebsaufgabe dar. Eine bestimmte Implementierungsklasse von Callable kann in Futuretask übergeben werden, was auf das Ergebnis dieser asynchronen Operation warten kann, um festzustellen, ob sie abgeschlossen wurde, und die Aufgabe abzusagen. Da Futuretask auch eine Implementierungsklasse der Runnable -Schnittstelle ist, kann Futuretask auch im Thread -Pool platziert werden.
22. So finden Sie, welcher Thread die längste CPU in der Linux -Umgebung verwendet
Dies ist ein praktischeres Problem, und ich denke, dieses Problem ist sehr sinnvoll. Sie können das tun:
(1) Holen Sie sich die PID-, JPS- oder PS -EEF -Projekte des Projekts Grep Java, der zuvor erwähnt wurde
(2) Top -H -P -PID kann die Bestellung nicht geändert werden
Dadurch wird der Prozentsatz der CPU -Zeit, die das aktuelle Projekt für jeden Thread benötigt, ausdruiert. Beachten Sie, dass der hier LWP ist, der Threadnummer des nativen Threads des Betriebssystems. Mein Notebook -Berg setzt keine Java -Projekte in der Linux -Umgebung ein. Daher gibt es keine Möglichkeit, Screenshots und Demonstrationen aufzunehmen. Wenn das Unternehmen ein Projekt mit einer Linux -Umgebung bereitstellt, können Sie es versuchen.
Durch die Verwendung von "Top -H -P PID" + "JPS PID" kann man leicht einen Fadenstapel finden, der eine hohe CPU einnimmt, wodurch der Grund für die Belegung einer hohen CPU positioniert wird, was im Allgemeinen auf unsachgemäße Codevorgänge zurückzuführen ist, die zu einer toten Schleife führen.
Lassen Sie mich schließlich erwähnen, dass der LWP mit "Top -H -P Pid" gespielt hat, und die lokale Threadnummer, die mit "JPS PID" gespielt wird, ist hexadezimal. Nach der Umwandlung können Sie den aktuellen Fadenstapel finden, der eine hohe CPU einnimmt.
23. Java -Programmierung schreiben Sie ein Programm, das Deadlock verursacht
Ich habe diese Frage zum ersten Mal gesehen und dachte, es sei eine sehr gute Frage. Viele Menschen wissen, wie Deadlock aussieht: Thread A und Thread B warten darauf, dass die Schlösser des anderen eine unendliche tote Schleife des Programms fortsetzen. Natürlich ist es nur darauf beschränkt. Wenn Sie fragen, wie Sie ein Deadlock -Programm schreiben, werden Sie es nicht wissen. Um es unverblümt auszudrücken, Sie verstehen nicht, was ein Deadlock ist. Wenn Sie eine Theorie verstehen, werden Sie getan. Im Grunde können Sie das Problem der Deadlock in der Praxis im Grunde nicht sehen.
Um wirklich zu verstehen, was ein Deadlock ist, ist diese Frage nicht schwierig, es gibt einige Schritte:
(1) Zwei Threads enthalten zwei Objektobjekte: Lock1 bzw. Lock2. Diese beiden Schlösser dienen als Schlösser für Synchroncodeblöcke.
(2) In der Run () -Methode von Thread 1 erhält der Synchronisationscode -Block zunächst die Objektsperrung von Lock1, Thread. Dies erfolgt hauptsächlich, um zu verhindern, dass Faden 1 kontinuierlich Objektschlösser von zwei Objekten erhalten: Lock1 und Lock2.
(3) Lauf von Thread 2) (In der Methode erhält der Synchronisationscodeblock zuerst das Objektsperr 2 und erwerbt dann die Objektsperrung.
Auf diese Weise hat nach dem Thread 1 "Sleeps" und Thread 2 das Object Lock2 erfasst. Thread 1 versucht zu diesem Zeitpunkt das Objekt Lock2 zu erwerben und wird blockiert. Zu diesem Zeitpunkt wird ein Deadlock gebildet. Ich werde den Code nicht mehr schreiben, er nimmt viel Platz ein. Java Multithreading 7: Deadlock Dieser Artikel enthält die Codeimplementierung der oben genannten Schritte.
24. Wie man einen blockierenden Faden aufweckt
Wenn der Faden blockiert, weil sie Warten (), Sleep () oder join () () aufrufen, kann er den Faden unterbrechen und ihn wecken, indem sie eine InterruptedException werfen. Wenn der Thread auf IO -Blockade trifft, ist er machtlos, da IO vom Betriebssystem implementiert wird und Java -Code das Betriebssystem nicht direkt kontaktieren kann.
25. Welche Hilfe hilft unveränderliche Objekte Multithreading?
Ein oben erwähntes Problem ist, dass unveränderliche Objekte die Sichtbarkeit der Speicher von Objekten sicherstellen und keine zusätzliche Synchronisation erforderlich ist, um unveränderliche Objekte zu lesen, was die Code -Ausführungseffizienz verbessert.
26. Was ist ein Multi-Thread-Kontextschalter?
Der Multithread -Kontext -Switching bezieht sich auf den Prozess des Schaltens der CPU -Steuerung von einem laufenden Thread zu einem anderen Thread und wartet auf die Erzielung der CPU -Ausführungsrechte.
27. Wenn die Thread -Pool -Warteschlange bei der Einreichung einer Aufgabe voll ist, was zu diesem Zeitpunkt passieren wird
Wenn Sie LinkedBlockingQueue verwenden, dh unbegrenzte Warteschlangen, spielt es keine Rolle. Fügen Sie weiterhin Aufgaben zur blockierenden Warteschlange hinzu und warten Sie auf die Ausführung, da LinkedBlockingCrossQueue fast als unendlich angesehen werden kann und unendlich Aufgaben speichern kann. Wenn Sie beispielsweise eine begrenzte Warteschlange verwenden, wird ArrayBlockingQueueue zuerst zum ArrayBlockingQueue hinzugefügt. Wenn das ArrayBlocking -Unternehmen voll ist, verwendet der AblehnungsexecutionHandler die Ablehnungsrichtlinie, um die vollständigen Aufgaben zu erledigen, und der Standard ist abortpolicy.
28. Was ist der Thread -Planungsalgorithmus, der in Java verwendet wird?
Präventivstil. Nachdem ein Thread die CPU verbraucht hat, berechnet das Betriebssystem eine Gesamtpriorität basierend auf Daten wie Thread -Priorität, Thread -Hunger usw. und zuteilt das nächste Mal in einen Thread zur Ausführung.
29. Was ist die Funktion von Thread.Sleep (0)
Diese Frage bezieht sich auf die obige Frage, und ich bin alle zusammen. Da Java einen präventiven Thread -Planungsalgorithmus verwendet, kann es auftreten, dass ein Thread häufig die CPU -Steuerung erhält. Um einige Threads mit einer relativ geringen Priorität zu ermöglichen, um die CPU -Steuerung zu erhalten, können Thread.Sleep (0) verwendet werden, um die Zeitscheiben des Betriebssystems manuell auszulösen. Dies ist auch ein Betrieb, um die CPU -Steuerung auszugleichen.
30. Was ist Spin
Viele synchronisierte Codes sind nur ein sehr einfacher Code, und die Ausführungszeit ist sehr schnell. Wenn Sie die zu diesem Zeitpunkt warten, können die Threads ein nicht lohnender Betrieb sein, da die Thread-Blockierung das Switchieren von Benutzern und Kernel-Zustand umfasst. Da der in synchronisierte Code sehr schnell ausgeführt wird, können Sie auch den Thread, der auf das Schloss warten, nicht blockiert werden, sondern stattdessen geschäftige Schleifen an der Grenze von Synchronized durchführen. Das ist Spin. Wenn Sie mehrere geschäftige Schleifen durchgeführt haben und feststellen, dass das Schloss nicht erhalten wurde, und es dann blockieren, kann dies eine bessere Strategie sein.
31. Was ist Java -Speichermodell?
Das Java-Speichermodell definiert eine Spezifikation für den Multi-Threading-Zugriff auf Java-Speicher. Das Java -Speichermodell muss vollständig erklärt werden, aber ich kann es hier in einigen Sätzen nicht klar erklären. Lassen Sie mich es kurz zusammenfassen.
Mehrere Teile des Java -Speichermodells:
(1) Das Java -Speichermodell unterteilt den Speicher in das Hauptgedächtnis und das Arbeitsspeicher. Der Zustand der Klasse, dh die zwischen den Klassen geteilten Variablen, werden im Hauptspeicher gespeichert. Jedes Mal, wenn ein Java -Thread diese Variablen im Hauptspeicher verwendet, wird die Variablen im Hauptspeicher gelesen und sie in seinem eigenen Arbeitsgedächtnis existieren. Wenn Sie einen eigenen Threadcode ausführen, verwendet er diese Variablen und betreibt den in seinem eigenen Arbeitsspeicher. Nachdem der Threadcode ausgeführt wurde, wird der neueste Wert auf den Hauptspeicher aktualisiert.
(2) Mehrere atomare Operationen werden definiert, um Variablen im Hauptspeicher und im Arbeitsspeicher zu betreiben
(3) Definieren Sie die Regeln für die Verwendung von flüchtigen Variablen
(4) passiert-dh das Prinzip des ersten Ereignisses definiert einige Regeln, in denen Operation A zuerst in Operation B auftreten muss. Zum Beispiel muss der Code vor dem Kontrollfluss im selben Thread zuerst im Code hinter dem Kontrollfluss auftreten. Wenn ein bestimmtes Stück Code nicht allen Vorschriften vorhanden ist, muss dieses Stück Code nicht sicher sein.
32. Was ist CAS?
CAS, vollständiger Name vergleichen und festgelegt, wird verglichen. Angenommen, es gibt drei Operanden: Speicherwert V, den alten erwarteten Wert A, der zu modifizierende Wert B. Wenn und nur wenn der erwartete Wert A und der Speicherwert V gleich sind, wird der Speicherwert an B geändert und true zurückgegeben, sonst wird nichts getan und falsch wird falsch zurückgegeben. Natürlich muss CAS mit der flüchtigen Variablen kooperieren, um sicherzustellen, dass die Variable, die jedes Mal erhalten wurde, der neueste Wert im Hauptspeicher ist. Andernfalls ist der alte erwartete Wert A immer ein Wert A, der sich für einen Thread nicht ändert. Solange eine bestimmte CAS -Operation fehlschlägt, wird sie niemals erfolgreich sein.
33. Was ist optimistisches Schloss und pessimistisches Schloss
(1) Optimistisches Schloss: Genau wie der Name ist es optimistisch, dass sich Probleme der Thread -Sicherheit durch gleichzeitige Operationen verursachen. Optimistic Lock ist der Ansicht, dass der Wettbewerb nicht immer auftritt. Daher muss er die Sperre nicht halten und vergleichen - setzen Sie diese beiden Aktionen als Atomoperation ein, um zu versuchen, Variablen im Speicher zu ändern. Wenn es fehlschlägt, bedeutet dies, dass ein Konflikt auftritt, und dann sollte es eine entsprechende Wiederholungslogik geben.
(2) Pessimistisches Schloss: Genau wie sein Name ist es pessimistisch in Bezug auf Fadensicherheitsprobleme durch gleichzeitige Operationen. Pessimistische Schlösser glauben, dass immer ein Wettbewerb auftreten wird. Jedes Mal, wenn eine Ressource betrieben wird, wird ein exklusives Schloss enthalten, genau wie synchronisiert, unabhängig davon, ob sie direkt gesperrt ist und die Ressource betrieben wird.
34. Was ist AQs?
Lassen Sie uns kurz über AQs sprechen. Der vollständige Name von AQS ist ein AbstractQueuedsychonizer. Es sollte ein abstrakter Warteschlangensynchronisator sein, wenn es übersetzt wird.
Wenn die Grundlage von Java.util.Concurrent CAS ist, ist AQS der Kern des gesamten Java -Parallelitätspakets und der Wiedereintrittsprotokolle, Countdownlatch, Semaphor usw. AQS verbindet tatsächlich den gesamten Eintrag in Form einer bidirektionalen Warteschlange. Zum Beispiel Reentrantlock. Alle wartenden Fäden werden in einen Eintrag platziert und in eine bidirektionale Warteschlange verbunden. Wenn der vorherige Thread Reentrantlock verwendet, wird der erste Eintrag der bidirektionalen Warteschlange tatsächlich ausgeführt.
AQS definiert alle Vorgänge in bidirektionalen Warteschlangen, öffnet jedoch nur die Trylock- und TryRelease -Methoden für Entwickler. Entwickler können die Trylock- und TryRelease -Methoden gemäß ihrer eigenen Implementierung umschreiben, um ihre eigenen Parallelitätsfunktionen zu implementieren.
35. Fadensicherheit des Singleton -Modus
Ein Klischee, das als erstes zu sagen ist, dass die Fadensicherheit des Singleton-Musters: Instanzen einer bestimmten Klasse nur einmal in einer Umgebung mit mehreren Threaden erstellt werden. Es gibt viele Möglichkeiten, das Singleton -Muster zu schreiben. Lassen Sie mich zusammenfassen:
(1) das Singleton -Muster des hungrigen Mannes schreiben: Fadensicherheit
(2) Lazy Singleton-Muster schreiben: Nicht-Thread-Safe
(3) Schreiben Sie den Singleton -Modus des Doppel -Check -Schloss: Thread -Sicherheit
36. Was ist die Funktion des Semaphors?
Semaphor ist ein Semaphor, und seine Funktion besteht darin, die Anzahl der Parallelität in einem bestimmten Codeblock zu begrenzen. Semaphor hat einen Konstruktor, der intareger n übergeben kann, was darauf hinweist, dass nur N -Threads auf ein bestimmtes Stück Code zugreifen können. Wenn N überschritten wird, warten Sie bitte, bis ein Thread den Codeblock abgeschlossen hat und den nächsten Thread eingeben. Daraus können wir sehen, dass, wenn die Int -Ganzzahl n = 1 im Semaphor -Konstruktor bestanden hat, gleichwertig dem Synchronisierungssynchronisation.
37. In der Hashtable -Methode der Größe () gibt es nur eine Anweisung "Rückgabezahl". Warum müssen Sie also noch synchronisieren?
Dies ist eine Verwirrung, die ich zuvor hatte, und ich frage mich, ob Sie über diese Frage nachgedacht haben. Wenn eine Methode mehrere Aussagen enthält und alle dieselbe Klassenvariable betreiben, wird dies zwangsläufig die Sicherheitsprobleme von Threads verursachen, wenn Sie keine Sperren in einer Umgebung mit mehreren Threads hinzufügen. Dies ist leicht zu verstehen, aber die Methode Size () hat eindeutig nur eine Aussage. Warum müssen Sie also noch Schlösser hinzufügen?
In Bezug auf dieses Problem habe ich es durch das Arbeiten und Lernen verstanden, und es gibt zwei Hauptgründe:
(1) Nur ein Thread kann die Synchronisationsmethode der festen Klasse gleichzeitig ausführen. Für die asynchrone Methode der Klasse können jedoch mehrere Threads gleichzeitig darauf zugreifen. Es gibt also ein Problem. Möglicherweise fügt Thread A Daten hinzu, wenn die Put -Methode von Hashtable ausgeführt wird, und Thread B kann die Methode der Größe () normalerweise aufrufen, um die Anzahl der aktuellen Elemente im Hashtable zu lesen. Der Wertwert ist möglicherweise nicht der neueste. Vielleicht hat Thread A die Daten hinzugefügt, aber ohne Größe ++ hat Thread B die Größe bereits gelesen. Für Thread B muss die Lesen der Größe ungenau sein. Nachdem die Synchronisation zur Größe () -Methode () Synchronisation hinzugefügt hat, wird die Methode Size () nur nach dem Thread A die Put -Methode aufruft
(2) Die CPU führt Code aus, ist jedoch kein Java -Code. Dies ist sehr wichtig und Sie müssen sich daran erinnern. Der Java -Code wird schließlich in den Assembly -Code für die Ausführung übersetzt, und der Assemblercode ist der Code, der wirklich mit Hardware -Schaltungen interagieren kann. Selbst wenn Sie sehen, dass es nur eine Zeile Java -Code gibt und selbst wenn Sie sehen, dass der Java -Code zusammengestellt wird, bedeutet dies nicht, dass für die zugrunde liegende Ebene nur eine Bytecode -Zeile generiert wird, die für diese Anweisung nur eine Operation gibt. Der Satz "Rückgabezahl" wird davon ausgegangen, dass er in drei zur Ausführung in drei Montageanweisungen übersetztes Übersetzung von Aussagen übersetzt wird, und es ist durchaus möglich, dass der Thread nach Ausführung des ersten Satzes wechselt.
38. Welcher Thread ist der Konstruktor der Thread -Klasse und der statische Block, der nach welchem Thread bezeichnet wird
Dies ist eine sehr schwierige und listige Frage. Bitte denken Sie daran: Der Konstruktor und der statische Block der Thread -Klasse werden vom Thread aufgerufen, in dem sich die neue Thread -Klasse befindet, und der Code in der Run -Methode wird vom Thread selbst aufgerufen.
Wenn die obige Erklärung Sie verwirrt, geben Sie mir ein Beispiel an, dass der neue Thread1 in Thread2 und neuer Thread2 in der Hauptfunktion ist, dann:
(1) Konstruktor und statischer Block von Thread2 werden vom Hauptfaden aufgerufen, und die Run () -Methode von Thread2 wird von Thread2 selbst aufgerufen
(2) Der Konstruktor und der statische Block von Thread1 werden von Thread2 aufgerufen, und die Run () -Methode von Thread1 wird von Thread1 selbst aufgerufen
39. Welches ist die bessere Wahl zwischen der Synchronisationsmethode und dem Synchronisationsblock?
Synchronisieren Sie Blöcke, was bedeutet, dass der Code außerhalb des Synchronisationsblocks asynchron ausgeführt wird, was die Effizienz des Codes effizienter verbessert als die gesamte Methode. Bitte kennen Sie ein Prinzip: der weniger Synchronisationsbereich
Desto besser.
In diesem Artikel möchte ich erwähnen, dass es zwar umso besser eine Optimierungsmethode gibt, die in Java -virtuellen Maschinen, obwohl kleiner der Synchronisationsbereich, desto besser ist, um den Synchronisationsbereich zu erhöhen. Das ist nützlich. Zum Beispiel ist StringBuffer eine Thread-Safe-Klasse. Natürlich ist die am häufigsten verwendete ANHECT () -Methode eine Synchronisationsmethode. Wenn wir Code schreiben, werden wir die Zeichenfolge wiederholt anhängen, was bedeutet, wiederholt zu sperren -> Entsperrung, was nicht gut für die Leistung ist, da dies bedeutet, dass die java -virtuelle Maschine wiederholt zwischen Kernel -Status und Benutzerzustand in diesem Thread wechseln muss. Daher führt der Java Virtual Machine einen Lock-Koarse-Vorgang im Code aus, der von mehreren Anhaft-Methoden aufgerufen wird, wobei mehrere Anhängevorgänge auf den Kopf und den Schwanz der Anhangsmethode erweitert und in einen großen Synchronisationsblock umgewandelt werden. Dies verringert die Anzahl der Sperren-> Entsperrenzeiten und verbessert die Effizienz der Codeausführung effektiv.
40. Wie kann man Threadpools für Unternehmen mit hoher Parallelität und kurzer Ausführungszeit verwenden? Wie benutze ich Threadpools für Unternehmen mit geringer Parallelität und langer Aufgabenausführung? Wie benutze ich Thread -Pools für Unternehmen mit hoher Parallelität und langer Serviceausführungszeit?
Dies ist eine Frage, die ich auf der gleichzeitigen Programmierwebsite gesehen habe. Ich stelle diese Frage an und hoffe, dass jeder sie sehen und darüber nachdenken kann, weil diese Frage sehr gut, sehr praktisch und sehr professionell ist. In Bezug auf dieses Thema lautet meine persönliche Meinung:
(1) Die Anzahl der Thread -Pool -Threads mit hoher Parallelität und kurzer Aufgabenausführungszeit kann auf die CPU -Kernnummer +1 eingestellt werden, um das Umschalten des Thread -Kontextes zu verringern
(2)并发不高、任务执行时间长的业务要区分开看:
a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务
b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
(3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。
Java线程阻塞(Blocked)的类型:
调用sleep函数进入睡眠状态,Thread.sleep(1000)或者TimeUnit.SECONDS.sleep(1),sleep不会释放锁。
等待(wait)某个事件,分为两种,(wait,notify,notifyAll),(await, signal,signalAll) ,后面会详细介绍。wait和await会释放锁,且必须在获取到锁的环境才能调用。
等待锁,synchronized和lock环境中,锁已经被别的线程拿走,等待获取锁。
IO阻塞(Blocked),比如网络等待,文件打开,控制台读取。System.in.read()。