JavaRush /Java-Blog /Random-DE /Die 50 wichtigsten Fragen und Antworten zu Java Core-Inte...

Die 50 wichtigsten Fragen und Antworten zu Java Core-Interviews. Teil 3

Veröffentlicht in der Gruppe Random-DE
Die 50 wichtigsten Fragen und Antworten zu Java Core-Interviews. Teil 1: Die 50 wichtigsten Fragen und Antworten zu Java Core-Interviews. Teil 2

Multithreading

37. Wie erstelle ich einen neuen Thread (Flow) in Java?

Auf die eine oder andere Weise erfolgt die Erstellung durch die Verwendung der Thread-Klasse. Aber vielleicht gibt es hier Optionen...
  1. Wir erben vonjava.lang.Thread
  2. Wir implementieren eine Schnittstelle , deren Objekt eine Konstruktorklasse java.lang.RunnableakzeptiertThread
Lassen Sie uns über jeden von ihnen sprechen.

Wir erben von der Thread-Klasse

Damit dies funktioniert, erben wir in unserer Klasse von java.lang.Thread. Es enthält Meth run(), genau das, was wir brauchen. Das gesamte Leben und die gesamte Logik des neuen Threads werden in dieser Methode enthalten sein. Dies ist eine Art mainMethode für einen neuen Thread. Danach müssen Sie nur noch ein Objekt unserer Klasse erstellen und die Methode ausführen start(), die einen neuen Thread erstellt und die darin geschriebene Logik ausführt. Lass uns nachsehen:
/**
* Пример того, Wie создавать треды путем наследования {@link Thread} класса.
*/
class ThreadInheritance extends Thread {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance threadInheritance1 = new ThreadInheritance();
       ThreadInheritance threadInheritance2 = new ThreadInheritance();
       ThreadInheritance threadInheritance3 = new ThreadInheritance();
       threadInheritance1.start();
       threadInheritance2.start();
       threadInheritance3.start();
   }
}
Die Ausgabe an die Konsole sieht folgendermaßen aus:

Thread-1
Thread-0
Thread-2
Das heißt, auch hier sehen wir, dass die Threads nicht nacheinander ausgeführt werden, sondern wie von der JVM entschieden.)

Implementierung der Runnable-Schnittstelle

Wenn Sie gegen die Vererbung sind und/oder bereits eine der anderen Klassen erben, können Sie die verwenden java.lang.Runnable. Hier in unserer Klasse implementieren wir diese Schnittstelle und implementieren die Methode run(), wie es in diesem Beispiel war. Sie müssen lediglich weitere Objekte erstellen Thread. Es scheint, dass mehr Zeilen schlechter sind. Aber wir wissen, wie schädlich eine Vererbung ist und dass man sie unbedingt vermeiden sollte ;) Schauen wir mal:
/**
* Пример того, Wie создавать треды из интерфейса {@link Runnable}.
* Здесь проще простого - реализуем этот интерфейс и потом передаем в конструктор
* экземпляр реализуемого ein Objektа.
*/
class ThreadInheritance implements Runnable {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance runnable1 = new ThreadInheritance();
       ThreadInheritance runnable2 = new ThreadInheritance();
       ThreadInheritance runnable3 = new ThreadInheritance();

       Thread threadRunnable1 = new Thread(runnable1);
       Thread threadRunnable2 = new Thread(runnable2);
       Thread threadRunnable3 = new Thread(runnable3);

       threadRunnable1.start();
       threadRunnable2.start();
       threadRunnable3.start();
   }
}
Und das Ausführungsergebnis:

Thread-0
Thread-1
Thread-2

38. Was ist der Unterschied zwischen einem Prozess und einem Thread?

Die 50 wichtigsten Fragen und Antworten zu Java Core-Interviews.  Teil 3 - 1Es gibt folgende Unterschiede zwischen einem Prozess und einem Thread:
  1. Ein ausgeführtes Programm wird als Prozess bezeichnet, während ein Thread eine Teilmenge eines Prozesses ist.
  2. Prozesse sind unabhängig, während Threads eine Teilmenge eines Prozesses sind.
  3. Prozesse haben unterschiedliche Adressräume im Speicher, während Threads einen gemeinsamen Adressraum enthalten.
  4. Der Kontextwechsel ist zwischen Threads im Vergleich zu Prozessen schneller.
  5. Die Kommunikation zwischen Prozessen ist langsamer und teurer als die Kommunikation zwischen Threads.
  6. Änderungen im übergeordneten Prozess wirken sich nicht auf den untergeordneten Prozess aus, wohingegen Änderungen im übergeordneten Thread Auswirkungen auf den untergeordneten Thread haben können.

39. Was sind die Vorteile von Multithreading?

Die 50 wichtigsten Fragen und Antworten zu Java Core-Interviews.  Teil 3 - 2
  1. Durch Multithreading kann eine Anwendung/ein Programm immer auf Eingaben reagieren, auch wenn bereits einige Hintergrundaufgaben ausgeführt werden.
  2. Mit Multithreading können Sie Aufgaben schneller erledigen, da die Threads unabhängig voneinander ausgeführt werden.
  3. Multithreading bietet eine bessere Cache-Auslastung, da Threads gemeinsame Speicherressourcen teilen;
  4. Multithreading reduziert den Serverbedarf, da ein Server mehrere Threads gleichzeitig ausführen kann.

40. Welche Zustände gibt es im Lebenszyklus eines Threads?

Die 50 wichtigsten Fragen und Antworten zu Java Core-Interviews.  Teil 3 - 3
  1. Neu: In diesem Zustand wird ein Klassenobjekt Threadmit dem neuen Operator erstellt, der Thread existiert jedoch nicht. Der Thread startet erst, wenn wir die aufrufen start().
  2. Ausführbar: In diesem Zustand ist der Thread nach dem Aufruf der Methode zur Ausführung bereit Start(). Es wurde jedoch noch nicht vom Thread-Scheduler ausgewählt.
  3. Läuft: In diesem Zustand wählt der Thread-Scheduler einen Thread aus dem Bereitschaftszustand aus und führt ihn aus.
  4. Warten/Blockiert: In diesem Zustand wird der Thread nicht ausgeführt, ist aber noch aktiv oder wartet auf den Abschluss eines anderen Threads.
  5. Tot/Beendet: Wenn die Methode beendet wird, run()befindet sich der Thread in einem beendeten oder toten Zustand.

41. Ist es möglich, einen Thread zweimal zu starten?

Nein, wir können den Thread nicht neu starten, denn sobald der Thread gestartet und ausgeführt wird, geht er in den Dead-Zustand über. Wenn wir also versuchen, den Thread zweimal auszuführen, wird eine runtimeException „ java.lang.IllegalThreadStateException “ ausgelöst. Lass uns nachsehen:
class DoubleStartThreadExample extends Thread {

   /**
    * Имитируем работу треда
    */
   public void run() {
	// что-то происходит. Для нас не существенно на этом этапе
   }

   /**
    * Запускаем тред дважды
    */
   public static void main(String[] args) {
       DoubleStartThreadExample doubleStartThreadExample = new DoubleStartThreadExample();
       doubleStartThreadExample.start();
       doubleStartThreadExample.start();
   }
}
Sobald die Arbeit den zweiten Anfang desselben Threads erreicht, gibt es eine Ausnahme. Probieren Sie es selbst aus ;) Es ist besser, einmal zu sehen, als hundertmal zu hören.

42. Was passiert, wenn Sie die run()-Methode direkt aufrufen, ohne die start()-Methode aufzurufen?

Ja, run()natürlich können Sie eine Methode aufrufen, aber dadurch wird kein neuer Thread erstellt und als separater Thread ausgeführt. In diesem Fall handelt es sich um ein einfaches Objekt, das eine einfache Methode aufruft. Wenn wir über die Methode sprechen start(), dann ist das eine andere Sache. Indem Sie diese Methode starten, runtimestartet sie eine neue und führt wiederum unsere Methode aus ;) Wenn Sie mir nicht glauben, versuchen Sie es:
class ThreadCallRunExample extends Thread {

   public void run() {
       for (int i = 0; i < 5; i++) {
           System.out.print(i);
       }
   }

   public static void main(String args[]) {
       ThreadCallRunExample runExample1 = new ThreadCallRunExample();
       ThreadCallRunExample runExample2 = new ThreadCallRunExample();

       // просто будут вызваны в потоке main два метода, один за другим.
       runExample1.run();
       runExample2.run();
   }
}
Und die Ausgabe an die Konsole sieht folgendermaßen aus:

0123401234
Es ist ersichtlich, dass kein Thread erstellt wurde. Alles funktionierte wie in einem normalen Unterricht. Zuerst funktionierte die Methode der ersten Klasse, dann die zweite.

43. Was ist ein Daemon-Thread?

Die 50 wichtigsten Fragen und Antworten zu Java Core-Interviews.  Teil 3 - 4Daemon-Thread (im Folgenden als Daemon-Thread bezeichnet) ist ein Thread, der Aufgaben im Hintergrund in Bezug auf einen anderen Thread ausführt. Das heißt, seine Aufgabe besteht darin, Hilfsaufgaben auszuführen, die nur in Verbindung mit einem anderen (Haupt-)Thread erledigt werden müssen. Es gibt viele Daemon-Threads, die automatisch funktionieren, z. B. Garbage Collector, Finalizer usw.

Warum schließt Java den Daemon-Thread?

Der einzige Zweck eines Daemon-Threads besteht darin, dem Benutzer-Thread Dienste für Hintergrundunterstützungsaufgaben bereitzustellen. Wenn der Hauptthread abgeschlossen ist, schließt die Laufzeit daher automatisch alle Daemon-Threads.

Methoden zum Arbeiten in der Thread-Klasse

Die Klasse java.lang.Threadstellt zwei Methoden zum Arbeiten mit dem Thread-Daemon bereit:
  1. public void setDaemon(boolean status)– gibt an, dass es sich um einen Daemon-Thread handelt. Der Standardwert ist false, was bedeutet, dass Nicht-Daemon-Threads erstellt werden, sofern nicht separat angegeben.
  2. public boolean isDaemon()– Im Wesentlichen ist dies ein Getter für die Variable daemon, die wir mit der vorherigen Methode festgelegt haben.
Beispiel:
class DaemonThreadExample extends Thread {

   public void run() {
       // Проверяет, демон ли этот поток oder нет
       if (Thread.currentThread().isDaemon()) {
           System.out.println("daemon thread");
       } else {
           System.out.println("user thread");
       }
   }

   public static void main(String[] args) {
       DaemonThreadExample thread1 = new DaemonThreadExample();
       DaemonThreadExample thread2 = new DaemonThreadExample();
       DaemonThreadExample thread3 = new DaemonThreadExample();

       // теперь thread1 - поток-демон.
       thread1.setDaemon(true);

       System.out.println("демон?.. " + thread1.isDaemon());
       System.out.println("демон?.. " + thread2.isDaemon());
       System.out.println("демон?.. " + thread3.isDaemon());

       thread1.start();
       thread2.start();
       thread3.start();
   }
}
Konsolenausgabe:

демон?.. true
демон?.. false
демон?.. false
daemon thread
user thread
user thread
Aus der Ausgabe sehen wir, dass wir innerhalb des Threads selbst mithilfe einer statischen currentThread()Methode einerseits herausfinden können, um welchen Thread es sich handelt, andererseits können wir es herausfinden, wenn wir einen Verweis auf das Objekt dieses Threads haben direkt daraus. Dies gibt die nötige Flexibilität in der Konfiguration.

44. Ist es möglich, einen Thread nach seiner Erstellung zu einem Daemon zu machen?

Nein. Wenn Sie dies tun, wird eine Ausnahme ausgelöst IllegalThreadStateException. Daher können wir einen Daemon-Thread nur vor dem Start erstellen. Beispiel:
class SetDaemonAfterStartExample extends Thread {

   public void run() {
       System.out.println("Working...");
   }

   public static void main(String[] args) {
       SetDaemonAfterStartExample afterStartExample = new SetDaemonAfterStartExample();
       afterStartExample.start();

       // здесь будет выброшено исключение
       afterStartExample.setDaemon(true);
   }
}
Konsolenausgabe:

Working...
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.setDaemon(Thread.java:1359)
	at SetDaemonAfterStartExample.main(SetDaemonAfterStartExample.java:14)

45. Was ist ein Shutdownhook?

Shutdownhook ist ein Thread, der implizit aufgerufen wird, bevor die JVM (Java Virtual Machine) heruntergefahren wird. Wir können es also verwenden, um eine Ressource zu bereinigen oder den Status zu speichern, wenn die Java Virtual Machine normal oder plötzlich heruntergefahren wird. Wir können shutdown hookmit der folgenden Methode hinzufügen:
Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());
Wie im Beispiel gezeigt:
/**
* Программа, которая показывает Wie запустить shutdown hook тред,
* который выполнится аккурат до окончания работы JVM
*/
class ShutdownHookThreadExample extends Thread {

   public void run() {
       System.out.println("shutdown hook задачу выполнил");
   }

   public static void main(String[] args) {

       Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());

       System.out.println("Теперь программа засыпает, нажмите ctrl+c чтоб завершить ее.");
       try {
           Thread.sleep(60000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
Konsolenausgabe:

Теперь программа засыпает, нажмите ctrl+c чтоб завершить ее.
shutdown hook задачу выполнил

46. ​​​​Was ist Synchronisation?

Unter Synchronisierung versteht man in Java die Möglichkeit, den Zugriff mehrerer Threads auf eine beliebige gemeinsam genutzte Ressource zu steuern. Wenn mehrere Threads versuchen, dieselbe Aufgabe auszuführen, besteht die Möglichkeit eines fehlerhaften Ergebnisses. Um dieses Problem zu lösen, verwendet Java die Synchronisierung, wodurch jeweils nur ein Thread arbeiten kann. Die Synchronisierung kann auf drei Arten erreicht werden:
  • Synchronisierungsmethode
  • Durch Synchronisieren eines bestimmten Blocks
  • Statische Synchronisierung

Methodensynchronisation

Die synchronisierte Methode wird verwendet, um ein Objekt für eine beliebige gemeinsam genutzte Ressource zu sperren. Wenn ein Thread eine synchronisierte Methode aufruft, erwirbt er automatisch eine Sperre für dieses Objekt und gibt sie frei, wenn der Thread seine Aufgabe abgeschlossen hat. Damit es funktioniert, müssen Sie das synchronisierte Schlüsselwort hinzufügen . Sehen wir uns anhand eines Beispiels an, wie das funktioniert:
/**
* Пример, где мы синхронизируем метод. То есть добавляем ему слово synchronized.
* Есть два писателя, которые хотят использовать один принтер. Они подготовoder свои поэмы
* И конечно же не хотят, чтоб их поэмы перемешались, а хотят, чтоб работа была сделана по * * * очереди для каждого из них
*/
class Printer {

   synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {
       // один ein Objekt для двух тредов
       Printer printer  = new Printer();

       // создаем два треда
       Writer1 writer1 = new Writer1(printer);
       Writer2 writer2 = new Writer2(printer);

       // запускаем их
       writer1.start();
       writer2.start();
   }
}

/**
* Писатель номер 1, который пишет свою поэму.
*/
class Writer1 extends Thread {
   Printer printer;

   Writer1(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<string> poem = Arrays.asList("Я ", this.getName(), " Пишу", " Письмо");
       printer.print(poem);
   }

}

/**
* Писатель номер 2, который пишет свою поэму.
*/
class Writer2 extends Thread {
   Printer printer;

   Writer2(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<String> poem = Arrays.asList("Не Я ", this.getName(), " Не пишу", " Не Письмо");
       printer.print(poem);
   }
}
Und die Ausgabe an die Konsole:

Я Thread-0 Пишу Письмо
Не Я Thread-1 Не пишу Не Письмо

Synchronisationsblock

Ein synchronisierter Block kann verwendet werden, um eine Synchronisierung für eine bestimmte Methodenressource durchzuführen. Nehmen wir an, dass Sie in einer großen Methode (ja, ja, so etwas kann man nicht schreiben, aber manchmal passiert es) aus irgendeinem Grund nur einen kleinen Teil synchronisieren müssen. Wenn Sie alle Codes einer Methode in einen synchronisierten Block einfügen, funktioniert dieser genauso wie eine synchronisierte Methode. Die Syntax sieht so aus:
synchronized (“ein Objekt для блокировки”) {
   // сам Code, который нужно защитить
}
Um das vorherige Beispiel nicht zu wiederholen, erstellen wir Threads über anonyme Klassen – das heißt, wir implementieren sofort die Runnable-Schnittstelle.
/**
* Вот Wie добавляется блок синхронизации.
* Внутри нужно указать у кого будет взят мьютекс для блокировки.
*/
class Printer {

   void print(List<String> wordsToPrint) {
       synchronized (this) {
           wordsToPrint.forEach(System.out::print);
       }
       System.out.println();
   }

   public static void main(String args[]) {
       // один ein Objekt для двух тредов
       Printer printer = new Printer();

       // создаем два треда
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("Я ", "Writer1", " Пишу", " Письмо");
               printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("Не Я ", "Writer2", " Не пишу", " Не Письмо");
               printer.print(poem);
           }
       });

       // запускаем их
       writer1.start();
       writer2.start();
   }
}

}
und Ausgabe an die Konsole

Я Writer1 Пишу Письмо
Не Я Writer2 Не пишу Не Письмо

Statische Synchronisierung

Wenn Sie eine statische Methode synchronisieren, gilt die Sperre für die Klasse und nicht für das Objekt. In diesem Beispiel wenden wir das synchronisierte Schlüsselwort auf eine statische Methode an, um eine statische Synchronisierung durchzuführen:
/**
* Вот Wie добавляется блок синхронизации.
* Внутри нужно указать у кого будет взят мьютекс для блокировки.
*/
class Printer {

   static synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {

       // создаем два треда
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("Я ", "Writer1", " Пишу", " Письмо");
               Printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("Не Я ", "Writer2", " Не пишу", " Не Письмо");
               Printer.print(poem);
           }
       });

       // запускаем их
       writer1.start();
       writer2.start();
   }
}
und die Ausgabe an die Konsole:

Не Я Writer2 Не пишу Не Письмо
Я Writer1 Пишу Письмо

47. Was ist eine volatile Variable?

Das Schlüsselwort volatilewird in der Multithread-Programmierung verwendet, um Thread-Sicherheit zu gewährleisten, da eine Änderung an einer veränderbaren Variablen für alle anderen Threads sichtbar ist, sodass jeweils eine Variable von jeweils einem Thread verwendet werden kann. Mit dem Schlüsselwort volatilekönnen Sie garantieren, dass die Variable threadsicher ist und im gemeinsam genutzten Speicher gespeichert wird und Threads sie nicht in ihren Cache aufnehmen. Wie sieht es aus?
private volatile AtomicInteger count;
Wir ergänzen einfach die Variable volatile. Dies bedeutet jedoch nicht vollständige Thread-Sicherheit ... Schließlich sind Operationen möglicherweise nicht atomar für eine Variable. Sie können jedoch AtomicKlassen verwenden, die die Operation atomar ausführen, also in einer einzigen Ausführung durch den Prozessor. Viele solcher Klassen sind im Paket zu finden java.util.concurrent.atomic.

48. Was ist Deadlock?

Deadlock ist in Java Teil des Multithreadings. Ein Deadlock kann in einer Situation auftreten, in der ein Thread auf eine Objektsperre wartet, die von einem anderen Thread erworben wurde, und ein zweiter Thread auf eine Objektsperre wartet, die vom ersten Thread erworben wurde. Daher warten diese beiden Threads aufeinander und führen ihren Code nicht weiter aus. Die 50 wichtigsten Fragen und Antworten zu Java Core-Interviews.  Teil 3 - 5Schauen wir uns ein Beispiel an, in dem es eine Klasse gibt, die Runnable implementiert. Es akzeptiert zwei Ressourcen in seinem Konstruktor. Innerhalb der run()-Methode übernimmt sie nacheinander die Sperre für sie. Wenn Sie also zwei Objekte dieser Klasse erstellen und die Ressourcen in unterschiedlicher Reihenfolge übertragen, kann es leicht zu einer Sperre kommen:
class DeadLock {

   public static void main(String[] args) {
       final Integer r1 = 10;
       final Integer r2 = 15;

       DeadlockThread threadR1R2 = new DeadlockThread(r1, r2);
       DeadlockThread threadR2R1 = new DeadlockThread(r2, r1);

       new Thread(threadR1R2).start();
       new Thread(threadR2R1).start();
   }
}

/**
* Класс, который принимает два ресурса.
*/
class DeadlockThread implements Runnable {

   private final Integer r1;
   private final Integer r2;

   public DeadlockThread(Integer r1, Integer r2) {
       this.r1 = r1;
       this.r2 = r2;
   }

   @Override
   public void run() {
       synchronized (r1) {
           System.out.println(Thread.currentThread().getName() + " захватил ресурс: " + r1);

           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           synchronized (r2) {
               System.out.println(Thread.currentThread().getName() + " захватил ресурс: " + r2);
           }
       }
   }
}
Konsolenausgabe:

Первый тред захватил первый ресурс
Второй тред захватывает второй ресурс

49. Wie vermeide ich einen Deadlock?

Basierend auf dem, was wir wissen, wie ein Deadlock auftritt, können wir einige Schlussfolgerungen ziehen ...
  • Wie im Beispiel oben gezeigt, war der Deadlock auf die Verschachtelung von Sperren zurückzuführen. Das heißt, innerhalb einer Schleuse gibt es eine andere oder mehrere. Dies kann auf folgende Weise vermieden werden: Anstatt zu verschachteln, müssen Sie oben eine neue Abstraktion hinzufügen, die Sperre einer höheren Ebene zuweisen und verschachtelte Sperren entfernen.
  • Je mehr Blockierungen vorhanden sind, desto größer ist die Wahrscheinlichkeit, dass es zu einem Deadlock kommt. Daher müssen Sie jedes Mal, wenn Sie eine Sperre hinzufügen, darüber nachdenken, ob diese wirklich benötigt wird und ob das Hinzufügen einer neuen Sperre vermieden werden kann.
  • Verwendet Thread.join(). Ein Deadlock kann auch auftreten, wenn ein Thread auf einen anderen wartet. Um dieses Problem zu vermeiden, können Sie die Methode zeitlich begrenzen join().
  • Wenn wir einen Thread haben, wird es keinen Deadlock geben ;)

50. Was ist eine Rennbedingung?

Wenn in echten Rennen die Autos Leistung erbringen, dann leisten Threads in der Rennterminologie des Multithreadings Leistung in den Rennen. Aber warum? Es werden zwei Threads ausgeführt, die auf dasselbe Objekt zugreifen können. Und sie können gleichzeitig versuchen, den Zustand zu aktualisieren. Bisher ist alles klar, oder? Die Threads arbeiten also entweder real parallel (wenn mehr als ein Kern im Prozessor vorhanden ist) oder bedingt parallel, wenn der Prozessor eine kurze Zeitspanne zuweist. Und wir können diese Prozesse nicht kontrollieren, daher können wir nicht garantieren, dass ein Thread, wenn er Daten von einem Objekt liest, Zeit hat, diese zu ändern, BEVOR ein anderer Thread dies tut. Probleme wie diese treten auf, wenn diese Test-and-Act-Kombination durchgeführt wird. Was bedeutet das? Wir haben zum Beispiel ifeinen Ausdruck, in dessen Körper sich die Bedingung selbst ändert, nämlich:
int z = 0;

// проверь
if (z < 5) {
//действуй
   z = z + 5;
}
Es kann also vorkommen, dass zwei Threads gleichzeitig in diesen Codeblock eintreten, während z noch gleich Null ist, und gemeinsam diesen Wert ändern. Und am Ende erhalten wir nicht den erwarteten Wert von 5, sondern 10. Wie kann man das vermeiden? Sie müssen vor und nach der Ausführung sperren. Das heißt, dass der erste Thread den Block betritt if, alle Aktionen ausführt, ihn ändert zund erst dann dem nächsten Thread die Möglichkeit gibt, dies zu tun. Aber der nächste Thread wird den Block nicht betreten if, da zer bereits 5 ist:
// получить блокировку для z
if (z < 5) {
   z = z + 5;
}
// выпустить из блокировки z
===================================================

Statt Ausgabe

Ich möchte mich bei allen bedanken, die bis zum Ende gelesen haben. Es war eine lange Reise und du hast es geschafft! Möglicherweise ist nicht alles klar. Es ist in Ordnung. Als ich anfing, Java zu lernen, konnte ich mir nicht mehr vorstellen, was eine statische Variable ist. Aber nichts, ich schlief mit diesem Gedanken ein, las noch ein paar Quellen und verstand es schließlich. Die Vorbereitung auf ein Vorstellungsgespräch ist eher eine akademische als eine praktische Angelegenheit. Deshalb müssen Sie vor jedem Vorstellungsgespräch Dinge wiederholen und Ihr Gedächtnis auffrischen, die Sie möglicherweise nicht oft verwenden.

Und wie immer nützliche Links:

Vielen Dank fürs Lesen. Bis bald.) Mein Profil auf GitHub
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION