Threads sind das Rückgrat des Multithreading. Wir leben in einer realen Welt, die an sich im Web gefangen ist, umgeben von vielen Anwendungen. Dasselbe gilt für die Weiterentwicklung von Technologien, die wir nicht mit der Geschwindigkeit kompensieren können, für die wir sie gleichzeitig ausführen müssen, für die wir mehr Anwendungen parallel ausführen müssen. Dies wird durch das Konzept des Fadens erreicht. 

Java-Multithreading-Tutorial

Beispiel aus dem wirklichen Leben 

Angenommen, Sie verwenden zwei Aufgaben gleichzeitig auf dem Computer, sei es mit Microsoft Word und dem Hören von Musik. Diese beiden Aufgaben werden als Prozesse bezeichnet . Sie fangen also an, Word zu tippen und gleichzeitig Musik da oben zu haben, das nennt man Multitasking . Wenn Sie jetzt einen Fehler in einem Word gemacht haben und die Rechtschreibprüfung eine Ausnahme anzeigt, bedeutet dies, dass selbst ein Word ein Prozess ist, der in Teilprozesse zerlegt ist. Wenn es sich bei einer Maschine um einen Dual-Core handelt, wird ein Prozess oder eine Aufgabe von einem Kern und Musik von einem anderen Kern verarbeitet. 

Im obigen Beispiel stoßen wir auf Multiprocessing und Multithreading, die irgendwie indirekt verwendet werden, um Multitasking zu erreichen. Wir haben auf diese Weise den Mechanismus der Aufteilung der Aufgaben als Multithreading bezeichnet, bei dem jeder Prozess oder jede Aufgabe von einem Thread aufgerufen wird, wobei ein Thread dafür verantwortlich ist, wann er ausgeführt wird, wann er stoppt und wie lange er sich in einem Wartezustand befindet. Daher ist ein Thread die kleinste Verarbeitungseinheit, während Multitasking ein Prozess ist, bei dem mehrere Aufgaben gleichzeitig ausgeführt werden.

Multitasking wird auf zwei Arten erreicht :

  1. Multiprocessing : Prozessbasiertes Multitasking ist ein schwergewichtiger Prozess und belegt verschiedene Adressräume im Speicher. Daher erfordert das Umschalten von einem Prozess zu einem anderen einige Zeit, sei es sehr klein, was zu einer Verzögerung beim Umschalten führt, da Register in Speicherabbildungen geladen und die Liste aktualisiert wird.
  2. Multithreading : Thread-basiertes Multitasking ist ein leichtgewichtiger Prozess und belegt denselben Adressraum. Daher werden beim Umschalten die Kommunikationskosten sehr gering sein.

Unten ist der Lebenszyklus eines Threads dargestellt worden

  1. Neu : Wenn ein Thread gerade erstellt wird.
  2. Ausführbar : Wenn eine start()-Methode über einen vom Thread-Scheduler verarbeiteten Thread aufgerufen wird.
    • Fall A: Kann ein laufender Thread sein
    • Fall B: Kann kein laufender Thread sein
  3. Running : Wenn Fall 1 erreicht wird, bedeutet dies, dass der Scheduler ausgewählt hat, dass der Thread vom lauffähigen Zustand in den lauffähigen Zustand ausgeführt werden soll.
  4. Blockiert : Wenn Fall 2 erreicht wird, bedeutet dies, dass der Planer ausgewählt hat, dass ein Thread den Status von lauffähig in lauffähig nicht ändern darf.
  5. Beendet : Wenn die Methode run() existiert oder die Methode stop() über einen Thread aufgerufen wird.

Wenn wir Threads in Betriebssysteme integrieren, kann man erkennen, dass die Prozessplanungsalgorithmen in Betriebssystemen stark nach dem gleichen Konzept arbeiten, das Threads in Gantt-Diagramme integriert . Einige der beliebtesten sind unten aufgeführt, die alle zusammenfassen und praktisch in der Softwareentwicklung verwendet werden.

  • Als Erster rein, als erster raus
  • Zuletzt rein, zuerst raus
  • Round-Robin-Planung

Nun stelle man sich das Konzept von Deadlock in Betriebssystemen mit Threads vor, wie die Umschaltung intern umgerechnet wird, wenn man sie nur im Überblick hat. 

Soweit wir Multithreading und Threads konzeptionell verstanden haben, können wir die Vorteile von Multithreading herausarbeiten, bevor wir uns mit anderen Konzepten oder Programmen im Multithreading befassen.

  • Der Benutzer wird nicht blockiert, da Threads unabhängig sind, selbst wenn es ein Problem mit einem Thread gibt, wird nur der entsprechende Prozess gestoppt, alle Operationen werden erfolgreich berechnet.
  • Spart Zeit, da zu viele Operationen gleichzeitig übertragen werden, was dazu führt, dass die Arbeit beendet wird, als ob Threads nicht verwendet werden, der einzige Prozess vom Prozessor behandelt wird.
  • Threads sind unabhängig, obwohl sie denselben Adressraum teilen.

Wir haben also alle Hauptkonzepte des Multithreading angesprochen, aber das Streben nach Fragen im Kopf bleibt. Warum brauchen wir es, wo und wie wird es eingesetzt? Nun werden alle drei Szenarien besprochen, warum Multithreading benötigt wird und wo es mithilfe von Programmen implementiert wird, in denen wir weiter mehr über Threads und ihre Methoden erfahren werden. Wir benötigen Multithreading in den vier aufgelisteten Szenarien.

  • Thread-Klasse
  • Mobile Anwendungen
    • Asynchroner Thread
  • Web Applikationen
  • Spielentwicklung

Hinweis: Standardmäßig haben wir nur einen Haupt-Thread, der für Haupt-Thread-Ausnahmen verantwortlich ist, auf die Sie gestoßen sind, auch ohne Vorkenntnisse in Multithreading

Zwei Möglichkeiten zur Implementierung von Multithreading

Methode 1: Thread-Klasse verwenden

Java stellt die Thread-Klasse bereit, um eine Programmierung zu erreichen, die Threads aufruft, wodurch einige Hauptmethoden der Thread-Klasse unten in tabellarischer Form gezeigt werden, mit denen wir uns häufig zusammen mit der von ihnen durchgeführten Aktion befassen.

Methoden Handlung ausgeführt
isDaemon()Es prüft, ob der aktuelle Thread ein Daemon ist oder nicht
Anfang()Es startet die Ausführung des Threads
Lauf()Es führt die ausführbaren Operationsanweisungen im Hauptteil dieser Methode über einen Thread aus
Schlaf()Es ist eine statische Methode, die den Thread für eine bestimmte Zeit in den Ruhezustand versetzt, die ihm als Argument übergeben wurde
warte ab()Es versetzt den Thread zurück in den Wartezustand.
benachrichtigen()Es gibt eine Benachrichtigung an einen Thread aus, der sich im Wartezustand befindet 
Alle benachrichtigen()Es gibt eine Benachrichtigung an alle Threads im Wartezustand aus 
setDaemon()Es setzt den aktuellen Thread als Daemon-Thread
halt()Es wird verwendet, um die Ausführung des Threads zu stoppen
fortsetzen()Es wird verwendet, um den unterbrochenen Thread fortzusetzen.

Voraussetzungen: Grundlegende Syntax und Methoden zum Umgang mit Threads

Lassen Sie uns nun überlegen, wie Sie den Namen des Threads festlegen. Standardmäßig heißen Threads Thread-0, Thread-1 usw. Aber es gibt auch eine Methode, die oft verwendet wird und als setName()- Methode bezeichnet wird. Auch entsprechend gibt es eine Methode getName() , die den Namen des Threads zurückgibt, sei es standardmäßig oder bereits mit der Methode setName() festgelegt . Die Syntax ist wie folgt:

Syntax: 

(a) Zurückgeben des Namens des Threads

public String getName() ;

(b) Den Namen des Threads ändern

 public void setName(String name);

Lassen Sie uns einen Schritt weiter gehen und in den Implementierungsteil eintauchen, um mehr Konzepte über Multithreading zu erwerben. Es gibt also grundsätzlich zwei Möglichkeiten, Multithreading zu implementieren:

Abbildung: Stellen Sie sich vor, man müsste alle Elemente mit 2 multiplizieren und es gibt 500 Elemente in einem Array.

Beispiele  

Java

// Case 1
// Java Program to illustrate Creation and execution of
// thread via start() and run() method in Single inheritance
 
// Class 1
// Helper thread Class extending main Thread Class
class MyThread1 extends Thread {
 
    // Method inside MyThread2
    // run() method which is called as
    // soon as thread is started
    public void run()
    {
 
        // Print statement when the thread is called
        System.out.println("Thread1 is running");
    }
}
 
// Class 2
// Main thread Class extending main Thread Class
class MyThread2 extends Thread {
 
    // Method inside MyThread2
    // run() method which is called
    // as soon as thread is started
    public void run()
    {
 
        // run() method which is called as soon as thread is
        // started
 
        // Print statement when the thread is called
        System.out.println("Thread2 is running");
    }
}
 
// Class 3
// Main Class
class GFG {
 
    // Main method
    public static void main(String[] args)
    {
 
        // Creating a thread object of our thread class
        MyThread1 obj1 = new MyThread1();
        MyThread2 obj2 = new MyThread2();
 
        // Getting the threads to the run state
 
        // This thread will transcend from runnable to run
        // as start() method will look for run() and execute
        // it
        obj1.start();
 
        // This thread will also transcend from runnable to
        // run as start() method will look for run() and
        // execute it
        obj2.start();
    }
}

Java

// Case 2
// Java Program to illustrate Difference between Runnable
// & Non-runnable Threads And Single Inheritance
 
// Class 1
// Helper thread Class extending main Thread Class
class MyThread1 extends Thread {
 
    // Method inside MyThread2
    // run() method which is called as soon as thread is
    // started
    public void run() {
 
        // Print statement when the thread is called
        System.out.println("Thread 1 is running");
    }
}
 
// Class 2
// Main thread Class extending main Thread Class
class MyThread2 extends Thread {
 
    // Method
    public void show() {
 
        // Print statement when thread is called
        System.out.println("Thread 2");
    }
}
 
// Class 3
// Main Class
class GFG {
 
    // Main method
    public static void main(String[] args) {
 
        // Creating a thread object of our thread class
        MyThread1 obj1 = new MyThread1();
        MyThread2 obj2 = new MyThread2();
 
        // Getting the threads to the run state
 
        // This thread will transcend from runnable to run
        // as start() method will look for run() and execute
        // it
        obj1.start();
 
        // This thread will now look for run() method which is absent
        // Thread is simply created not runnable
        obj2.start();
    }
}

Java

// Java Program to illustrate difference between
// start() method thread vs show() method
 
// Class 1
// Helper thread Class extending main Thread Class
class MyThread1 extends Thread {
 
    // Method inside MyThread2
    // run() method which is called as soon as thread is
    // started
    public void run() {
 
        // Print statement when the thread is called
        System.out.println("Thread 1 is running");
    }
}
 
// Class 2
// Main thread Class extending main Thread Class
class MyThread2 extends Thread {
 
    // Method
    public void show() {
 
        // Print statement when thread is called
        System.out.println("Thread 2");
    }
}
 
// Class 3
// Main Class
class GFG {
 
    // Main method
    public static void main(String[] args) {
 
        // Creating a thread object of our thread class
        MyThread1 obj1 = new MyThread1();
        MyThread2 obj2 = new MyThread2();
 
        // Getting the threads to the run state
 
        // This thread will transcend from runnable to run
        // as start() method will look for run() and execute
        // it
        obj1.start();
 
        // This thread is simply a function call as
        // no start() method is executed so here only
        // thread is created only followed by call
        obj2.show();
    }
}

 
 

Ausgabe:

Fall 1:

Thread1 is running
Thread2 is running

Hier haben wir unsere beiden Thread-Klassen für jeden Thread erstellt. In der Hauptmethode erstellen wir einfach Objekte dieser Thread-Klassen, wo Objekte jetzt Threads sind. Also rufen wir in main den Thread mit der Methode start() über beide Threads auf. Jetzt startet die start()-Methode den Thread und sucht nach ihrer run()-Methode, die ausgeführt werden soll. Hier hatten unsere beiden Thread-Klassen run()-Methoden, sodass beide Threads vom Scheduler von runnable in den Ausführungsstatus versetzt werden und die Ausgabe auf der Konsole gerechtfertigt ist.

Fall 2:

Thread 1 is running

Hier haben wir unsere beiden Thread-Klassen für jeden Thread erstellt. In der main-Methode erstellen wir einfach Objekte dieser Thread-Klassen, wo Objekte jetzt Threads sind. Also rufen wir im Wesentlichen den Thread mit der Methode start() für beide Threads auf. Jetzt startet die start()-Methode den Thread und sucht nach der auszuführenden run()-Methode. Hier verfügt nur Klasse 1 über die run()-Methode, um den Thread vom Runnable- in den Tun-Zustand zur Ausführung zu überführen, während Thread 2 vom Scheduler nur erstellt, aber nicht in den Run-Zustand versetzt wird, da die entsprechende run()-Methode fehlte. Daher wird nur Thread 1 aufgerufen Rest Thread 2 wird nur erstellt und wird im lauffähigen Zustand später vom Scheduler blockiert, da die entsprechende Methode run() fehlte.

Fall 3:

Thread 2
Thread 1 is running

Methode 2: Verwenden der ausführbaren Schnittstelle 

Eine andere Möglichkeit, Multithreading in Java zu erreichen, ist über die Runnable-Schnittstelle. Hier, wie wir im obigen Beispiel in Weg 1 gesehen haben, wo die Thread-Klasse erweitert wird. Hier hat die Runnable-Schnittstelle, die eine funktionale Schnittstelle ist, ihre eigene run()-Methode. Hier werden Klassen in die Runnable-Schnittstelle implementiert. Später wird in der main()-Methode eine Runnable-Referenz für die Klassen erstellt, die implementiert werden, um eine Bindung zwischen der Thread-Klasse herzustellen, um unsere eigenen entsprechenden run()-Methoden auszuführen. Außerdem übergeben wir beim Erstellen eines Objekts der Thread-Klasse diese Referenzen an die Thread-Klasse, da ihr Konstruktor ein nur ausführbares Objekt zulässt, das als Parameter übergeben wird, während das Thread-Klassenobjekt in einer main()-Methode erstellt wird. Nun zu guter Letzt wahrscheinlich das, was wir in der Thread-Klasse gemacht haben, start()-Methode wird über das ausführbare Objekt aufgerufen, das jetzt bereits mit Objekten der Thread-Klasse verknüpft ist, sodass die Ausführung für unsere run()-Methoden im Falle einer ausführbaren Schnittstelle beginnt. Dies wird im folgenden Programm wie folgt dargestellt:

Beispiel:

Java

// Java Program to illustrate Runnable Interface in threads
// as multiple inheritance is not allowed
 
// Importing basic packages
import java.io.*;
import java.util.*;
 
// Class 1
// Helper class implementing Runnable interface
class MyThread1 implements Runnable {
 
    // run() method inside this class
    public void run()
    {
        // Iterating to get more execution of threads
        for (int i = 0; i < 5; i++) {
 
            // Print statement whenever run() method
            // of this class is called
            System.out.println("Thread1");
 
            // Getting sleep method in try block to
            // check for any exceptions
            try {
                // Making the thread pause for a certain
                // time using sleep() method
                Thread.sleep(1000);
            }
 
            // Catch block to handle the exceptions
            catch (Exception e) {
            }
        }
    }
}
 
// Class 2
// Helper class implementing Runnable interface
class MyThread2 implements Runnable {
 
    // run() method inside this class
    public void run()
    {
        for (int i = 0; i < 5; i++) {
 
            // Print statement whenever run() method
            // of this class is called
            System.out.println("Thread2");
 
            // Getting sleep method in try block to
            // check for any exceptions
            try {
 
                // Making the thread pause for a certain
                // time
                // using sleep() method
                Thread.sleep(1000);
            }
 
            // Catch block to handle the exceptions
            catch (Exception e) {
            }
        }
    }
}
 
// Class 3
// Main class
public class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating reference of Runnable to
        // our classes above in main() method
        Runnable obj1 = new MyThread1();
        Runnable obj2 = new MyThread2();
 
        // Creating of of thread class
        // by passing object of Runnable in constructor o
        // Thread class
        Thread t1 = new Thread(obj1);
        Thread t2 = new Thread(obj2);
 
        // Starting the execution of our own run() method
        // in the classes above
        t1.start();
        t2.start();
    }
}

 
 

Ausgabe
Faden2
Faden1
Faden2
Faden1
Faden2
Faden1
Faden2
Faden1
Faden2
Faden1

Punkte, die Sie sich merken sollten: Wann immer Sie Threads erstellen möchten, gibt es nur zwei Möglichkeiten:

  1. Erweiterung der Klasse
  2. Implementieren der Schnittstelle, die lauffähig ist

Stellen Sie sicher, dass Sie ein Objekt von Threads erstellen, in dem Sie das Objekt von Runnable übergeben müssen 

Spezielle Methoden von Threads

Lassen Sie uns nun besprechen, dass es verschiedene Methoden für Threads gibt. Hier werden wir die wichtigsten diskutieren, um ein praktisches Verständnis von Threads und Multithreading zu haben, die wie folgt sequenziell sind:

  1. start()-Methode
  2. suspend()-Methode 
  3. stop()-Methode 
  4. wait()-Methode 
  5. Benachrichtigung() Methode 
  6. alertAll()-Methode
  7. sleep() Methode
    • Ausgabe ohne Methode sleep()
    • Ausgabe mit sleep()-Methode in Serial Execution Processes (Blocking-Methods-Ansatz)
    • Ausgabe mit der Methode sleep() in parallelen Ausführungsprozessen (Ansatz zur Entsperrung von Methoden)
  8. join()-Methode

Hinweis: Für naive Benutzer im Multithreading, wo Threads das Rückgrat sind, gehen Sie durch Programm 4, um die Grundlagen von Threads zu erfahren, wie man sie startet, hält oder beendet, wechseln Sie dann nur zu Programm 1 und ruhen Sie sich wie folgt aus.

Implementierung: 

Java

// Example 1
// Java Program to illustrate Output Without sleep() Method
 
// Class 1
// Helper Class 1
class Shot extends Thread {
 
    // Method 1
    public void show() {
 
        // Iterating to print more number of times
        for (int i = 0; i < 5; i++) {
 
            // Print statement whenever method
            // of this class is called
            System.out.println("Shot");
 
        }
    }
}
 
// Class 2
// Helper Class 2
class Miss extends Thread {
 
    // Method 2
    public void show() {
 
        // Iterating to print more number of times
        for (int i = 0; i < 5; i++) {
 
            // Print statement whenever method
            // of this class is called
            System.out.println("Miss");
 
        }
    }
 
}
 
// Class 3
// Main class
public class GFG {
 
    // Method 3
    // Main method
    public static void main(String[] args) {
 
        // Creating objects in the main() method
        // of class 1 and class 2
        Shot obj1 = new Shot();
        Miss obj2 = new Miss();
 
        // Calling methods of the class 1 and class 2
        obj1.show();
        obj2.show();
 
    }
}

Java

// Example 2
// Java Program to illustrate Output Using sleep() Method
// in Serial Execution
 
// Class 1
// Helper Class 1
class Shot extends Thread {
 
    // Method 1
    // public void show() {
    public void show()
    {
 
        // Iterating to print more number of times
        for (int i = 0; i < 5; i++) {
 
            // Print statement
            System.out.println("Shot");
 
            // Making thread to sleep using sleep() method
 
            // Try-catch block for exceptions
            try {
                Thread.sleep(1000);
            }
            catch (Exception e) {
            }
        }
    }
}
 
// Class 2
// Helper Class 2 Hello
class Miss extends Thread {
 
    // Method 2
    // public void show() {
    public void show()
    {
 
        // Iterating to print more number of times
        for (int i = 0; i < 5; i++) {
 
            // Print statement
            System.out.println("Miss");
 
            // Making thread to sleep using sleep() method
 
            // Try-catch block for exceptions
            try {
                Thread.sleep(1000);
            }
            catch (Exception e) {
            }
        }
    }
}
 
// Class 3
// Main class
public class GFG {
 
    // Method 3
    // Main method
    public static void main(String[] args)
    {
 
        // Creating objects in the main() method
        Shot obj1 = new Shot();
        Miss obj2 = new Miss();
 
        // Starting the thread objects
        obj1.start();
        obj2.start();
 
        // Calling methods of class 1 and class 2
        obj1.show();
        obj2.show();
    }
}

Java

// Example 3
// Java Program to illustrate Output Using sleep() Method
// in Parallel Execution
 
// Class 1
// Helper Class 1
class Shot extends Thread {
 
    // Method 1
    // public void show() {
    public void run()
    {
 
        // Iterating to print more number of times
        for (int i = 0; i < 5; i++) {
 
            // Print statement
            System.out.println("Shot");
 
            // Making thread to sleep using sleep() method
 
            // Try catch block for exceptions
            try {
                Thread.sleep(1000);
            }
            catch (Exception e) {
            }
        }
    }
}
 
// Class 2
// Helper Class 2 Hello
class Miss extends Thread {
 
    // Method 2
    // public void show() {
    public void run()
    {
 
        // Iterating to print more number of times
        for (int i = 0; i < 5; i++) {
 
            // Print statement
            System.out.println("Miss");
 
            // Making thread to sleep using sleep() method
 
            // Try catch block for exceptions
            try {
                Thread.sleep(1000);
            }
            catch (Exception e) {
            }
        }
    }
}
 
// Class 3
// Main class
public class GFG {
 
    // Method 3
    // Main method
    public static void main(String[] args)
    {
 
        // Creating objects in the main() method
        Shot obj1 = new Shot();
        Miss obj2 = new Miss();
 
        // Starting the thread objects
        // using start() method
 
        // start() method calls the run() method
        // automatically
        obj1.start();
        obj2.start();
    }
}

Ausgabe:

Fall 1:

Shot
Shot
Shot
Shot
Shot
Miss
Miss
Miss
Miss
Miss

Fall 2: V ideoausgabe

Shot
Shot
Shot
Shot
Shot
Miss
Miss
Miss
Miss
Miss

Fall 3: Videoausgabe 

Shot
Miss
Shot
Miss
Shot
Miss
Shot
Miss
Shot
Miss

Hinweis: Es wurde keine Priorität für Threads festgelegt, für die je nach Ausführungsreihenfolge der Threads die Ausgaben variieren. Denken Sie also an diesen Nachteil des Multithreadings verschiedener Ausgaben, der zu Dateninkonsistenzproblemen führt, die wir im späteren Teil ausführlich besprechen werden unter Synchronisation in Threads. 

Prioritäten in Threads

Prioritäten in Threads ist ein Konzept, bei dem jeder Thread eine Priorität hat, von der man in Laiensprache sagen kann, dass jedes Objekt hier Priorität hat, was durch Zahlen von 1 bis 10 dargestellt wird. 

  • Die Standardpriorität ist wie ausgenommen auf 5 eingestellt.
  • Die Mindestpriorität ist auf 0 gesetzt.
  • Die maximale Priorität ist auf 10 eingestellt.

Hier sind 3 Konstanten darin definiert und zwar wie folgt:

  1. public static int NORM_PRIORITY
  2. public static int MIN_PRIORITY
  3. public static int MAX_PRIORITY

Lassen Sie uns dies anhand eines Beispiels besprechen, um zu erfahren, wie die Arbeit intern ausgeführt wird. Hier werden wir das oben gesammelte Wissen wie folgt verwenden:

  • Wir werden die Methode currentThread() verwenden, um den Namen des aktuellen Threads zu erhalten. Der Benutzer kann auch die setName()- Methode verwenden, wenn er/sie zum Verständnis Threads nach Wahl benennen möchte.
  • Die Methode getName() wird verwendet, um den Namen des Threads zu erhalten.

Java

// Java Program to illustrate Priority Threads
// Case 1: No priority is assigned (Default priority)
 
// Importing input output thread class
import java.io.*;
// Importing Thread class from java.util package
import java.util.*;
 
// Class 1
// Helper Class (Our thread  class)
class MyThread extends Thread {
 
    public void run()
    {
 
        // Printing the current running thread via getName()
        // method using currentThread() method
        System.out.println("Running Thread : "
                           + currentThread().getName());
 
        // Print and display the priority of current thread
        // via currentThread() using getPriority() method
        System.out.println("Running Thread Priority : "
                           + currentThread().getPriority());
    }
}
 
// Class 2
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating objects of MyThread(above class)
        // in the main() method
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
 
        // Case 1: Default Priority no setting
        t1.start();
        t2.start();
    }
}

Java

// Java Program to illustrate Priority Threads
// Case 2: NORM_PRIORITY
 
// Importing input output thread class
import java.io.*;
// Importing Thread class from java.util package
import java.util.*;
 
// Class 1
// Helper Class (Our thread  class)
class MyThread extends Thread {
 
    // run() method to transit thread from
    // runnable to run state
    public void run()
    {
 
        // Printing the current running thread via getName()
        // method using currentThread() method
        System.out.println("Running Thread : "
                           + currentThread().getName());
 
        // Print and display the priority of current thread
        // via currentThread() using getPriority() method
        System.out.println("Running Thread Priority : "
                           + currentThread().getPriority());
    }
}
 
// Class 2
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating objects of MyThread(above class)
        // in the main() method
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
 
        // Setting priority to thread via NORM_PRIORITY
        // which set priority to 5 as default thread
        t1.setPriority(Thread.NORM_PRIORITY);
        t2.setPriority(Thread.NORM_PRIORITY);
 
        // Setting default priority using
        // NORM_PRIORITY
        t1.start();
        t2.start();
    }
}

Java

// Java Program to illustrate Priority Threads
// Case 3: MIN_PRIORITY
 
// Importing input output thread class
import java.io.*;
// Importing Thread class from java.util package
import java.util.*;
 
// Class 1
// Helper Class (Our thread  class)
class MyThread extends Thread {
 
    // run() method to transit thread from
    // runnable to run state
    public void run()
    {
 
        // Printing the current running thread via getName()
        // method using currentThread() method
        System.out.println("Running Thread : "
                           + currentThread().getName());
 
        // Print and display the priority of current thread
        // via currentThread() using getPriority() method
        System.out.println("Running Thread Priority : "
                           + currentThread().getPriority());
    }
}
 
// Class 2
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating objects of MyThread(above class)
        // in the main() method
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
 
        // Setting priority to thread via NORM_PRIORITY
        // which set priority to 1 as least priority thread
        t1.setPriority(Thread.MIN_PRIORITY);
        t2.setPriority(Thread.MIN_PRIORITY);
 
        // Setting default priority using
        // NORM_PRIORITY
        t1.start();
        t2.start();
    }
}

Java

// Java Program to illustrate Priority Threads
// Case 4: MAX_PRIORITY
 
// Importing input output thread class
import java.io.*;
// Importing Thread class from java.util package
import java.util.*;
 
// Class 1
// Helper Class (Our thread  class)
class MyThread extends Thread {
 
    // run() method to transit thread from
    // runnable to run state
    public void run()
    {
 
        // Printing the current running thread via getName()
        // method using currentThread() method
        System.out.println("Running Thread : "
                           + currentThread().getName());
 
        // Print and display the priority of current thread
        // via currentThread() using getPriority() method
        System.out.println("Running Thread Priority : "
                           + currentThread().getPriority());
    }
}
 
// Class 2
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating objects of MyThread(above class)
        // in the main() method
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
 
        // Setting priority to thread via MAX_PRIORITY
        // which set priority to 1 as most priority thread
        t1.setPriority(Thread.MAX_PRIORITY);
        t2.setPriority(Thread.MAX_PRIORITY);
 
        // Setting default priority using
        // MAX_PRIORITY
 
        // Starting the threads using start() method
        // which automatically invokes run() method
        t1.start();
        t2.start();
    }
}

Ausgabe:

Fall 1: Standardpriorität

Running Thread : Thread-0
Running Thread : Thread-1
Running Thread Priority : 5
Running Thread Priority : 5

Fall 2: NORM_PRIORITY

Running Thread : Thread-0
Running Thread : Thread-1
Running Thread Priority : 5
Running Thread Priority : 5

Fall 3: MIN_PRIORITY

Running Thread : Thread-0
Running Thread : Thread-1
Running Thread Priority : 1
Running Thread Priority : 1

Fall 4: MAX_PRIORITY

Running Thread : Thread-1
Running Thread : Thread-0
Running Thread Priority : 10
Running Thread Priority : 10

Erklärung der Ausgabe

Wenn wir genau hinschauen, sehen wir, dass die Ausgaben für die Fälle 1 und 2 äquivalent sind. Dies bedeutet, dass, wenn der Benutzer sich der Prioritätsthreads nicht einmal bewusst ist, NORM_PRIORITY immer noch dasselbe Ergebnis bis zur Standardpriorität anzeigt. Dies liegt daran, dass die Standardpriorität des Ausführens von Threads ausgeführt wird, sobald die entsprechende start() -Methode aufgerufen wird, indem die Prioritäten für alle Threads auf 5 gesetzt werden, was der Priorität des NORM-Falls entspricht. Dies liegt daran, dass beide Ausgänge einander äquivalent sind. Während in Fall 3 die Priorität auf einer Skala von 1 bis 10 auf ein Minimum eingestellt ist, tun Sie dasselbe in Fall 4, wo die Priorität auf der gleichen Skala 10 zugewiesen wird. 

Daher sind alle Ergebnisse in Bezug auf Prioritäten gerechtfertigt. Lassen Sie uns nun zu einem wichtigen Aspekt des Prioritäts-Threading übergehen, der in das tägliche Leben integriert wurde, der Daemon-Thread

Daemon-Thread ist im Grunde ein Service-Provider-Thread, der Dienste für den Benutzer-Thread bereitstellt. Der Geltungsbereich für diesen Thread start() oderterminate() hängt vollständig vom Thread des Benutzers ab, da er im Backend unterstützt, dass Benutzerthreads ausgeführt werden. Sobald der Benutzer-Thread beendet wird, wird auch der Daemon-Thread gleichzeitig mit dem Service-Provider-Thread beendet.

Daher sind die Eigenschaften des Daemon-Threads wie folgt:

  • Es ist nur der Dienstanbieter-Thread nicht für die Interpretation in Benutzer-Threads verantwortlich.
  • Es handelt sich also um einen Thread mit niedriger Priorität.
  • Es ist ein abhängiger Thread, da es keine eigene Existenz hat.
  • JVM beendet den Thread, sobald Benutzer-Threads beendet werden, und kommt wieder ins Spiel, wenn der Thread des Benutzers startet.
  • Ja, Sie vermuten, das beliebteste Beispiel ist Garbage Collector in Java. Einige andere Beispiele beinhalten „finalizer“.

Ausnahmen: IllegalArgumentException als Rückgabetyp beim Setzen eines Daemon-Threads ist boolesch, also wenden Sie es mit Bedacht an.

Hinweis: Um die Ausnahme zu beseitigen, sollte der Benutzer-Thread erst starten, nachdem er auf Daemon-Thread gesetzt wurde. Die andere Möglichkeit, vor dem Setzen auf Daemon zu starten, funktioniert nicht, da IllegalArgumentException auftaucht 

Wie oben in der Thread-Klasse besprochen, sind die beiden am häufigsten verwendeten Methoden wie folgt:

Daemon-Thread-Methoden Handlung ausgeführt 
isDaemon()Es prüft, ob der aktuelle Thread ein Daemon-Thread ist oder nicht 
setDaemon()Es hat den Thread so eingestellt, dass er als Daemon-Thread markiert wird

Lassen Sie uns die Implementierung des Daemon-Threads besprechen, bevor wir zum Garbage Collector springen.

Java

// Java Program to show Working of Daemon Thread
// with users threads
 
import java.io.*;
// Importing Thread class from java.util package
import java.util.*;
 
// Class 1
// Helper Class extending Thread class
class CheckingMyDaemonThread extends Thread {
 
    // Method
    // run() method which is invoked as soon as
    // thread start via start()
    public void run()
    {
 
        // Checking whether the thread is daemon thread or
        // not
        if (Thread.currentThread().isDaemon()) {
 
            // Print statement when Daemon thread is called
            System.out.println(
                "I am daemon thread and I am working");
        }
 
        else {
 
            // Print statement whenever users thread is
            // called
            System.out.println(
                "I am user thread and I am working");
        }
    }
}
 
// Class 2
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating threads in the main body
        CheckingMyDaemonThread t1
            = new CheckingMyDaemonThread();
        CheckingMyDaemonThread t2
            = new CheckingMyDaemonThread();
        CheckingMyDaemonThread t3
            = new CheckingMyDaemonThread();
 
        // Setting thread named 't2' as our Daemon thread
        t2.setDaemon(true);
 
        // Starting all 3 threads using start() method
        t1.start();
        t2.start();
        t3.start();
 
        // Now start() will automatically
        // invoke run() method
    }
}

Java

// Java Program to show Working of Daemon Thread
// with users threads where start() is invoked
// prior before setting thread to Daemon
 
import java.io.*;
// Basically we are importing Thread class
// from java.util package
import java.util.*;
 
// Class 1
// Helper Class extending Thread class
class CheckingMyDaemonThread extends Thread {
 
    // Method
    // run() method which is invoked as soon as
    // thread start via start()
    public void run()
    {
 
        // Checking whether the thread is daemon thread or
        // not
        if (Thread.currentThread().isDaemon()) {
 
            // Print statement when Daemon thread is called
            System.out.println(
                "I am daemon thread and I am working");
        }
 
        else {
 
            // Print statement whenever users thread is
            // called
            System.out.println(
                "I am user thread and I am working");
        }
    }
}
 
// Class 2
// Main Class
class GFG {
 
    // Method
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating threads objects of above class
        // in the main body
        CheckingMyDaemonThread t1
            = new CheckingMyDaemonThread();
        CheckingMyDaemonThread t2
            = new CheckingMyDaemonThread();
        CheckingMyDaemonThread t3
            = new CheckingMyDaemonThread();
 
        // Starting all 3 threads using start() method
        t1.start();
        t2.start();
        t3.start();
 
        // Now start() will automatically invoke run()
        // method
 
        // Now at last setting already running thread 't2'
        // as our Daemon thread will throw an exception
        t2.setDaemon(true);
    }
}

 
 

Eine andere Möglichkeit, dasselbe zu erreichen, ist die Thread-Gruppe , bei der, wie der Name schon sagt, mehrere Threads als ein einziges Objekt behandelt werden und später alle Operationen über dieses Objekt selbst ausgeführt werden, um einen Ersatz für den Thread-Pool bereitzustellen.  

Notiz: 

Beachten Sie bei der Implementierung von ThreadGroup, dass ThreadGroup ein Teil der Klasse ' java.lang.ThreadGroup' ist und nicht Teil der Thread-Klasse in Java. Schauen Sie sich also die Konstruktoren und Methoden der ThreadGroup-Klasse an, bevor Sie fortfahren, und überprüfen Sie daher veraltete Methoden in seiner Klasse um nicht weiter mit Unklarheiten konfrontiert zu werden. 

Hier ist die main()-Methode an sich ein Thread, aufgrund dessen Sie beim Ausführen des Programms eine Ausnahme in main() sehen, aufgrund dessen system.main-Thread-Ausnahme manchmal während der Ausführung des Programms ausgelöst wird.

Synchronisation

Es ist der Mechanismus, der den Zugriff mehrerer Threads auf die gemeinsame Nutzung einer gemeinsamen Ressource begrenzt und daher als nützlich vorgeschlagen wird, wenn jeweils nur einem Thread der Zugriff zum Überfahren gewährt wird.

Es wird im Programm durch das Schlüsselwort „ synced “ implementiert.

Lassen Sie uns nun endlich einige Vor- und Nachteile der Synchronisierung besprechen, bevor wir sie implementieren. Für mehr Tiefe in der Synchronisation kann man auch Sperren auf Objektebene und Sperren auf Klassenebene lernen und die Unterschiede zwischen beiden bemerken , um ein angemessenes Verständnis davon zu bekommen, bevor man sie implementiert.

Warum ist eine Synchronisation erforderlich?

  1. Dateninkonsistenzprobleme sind das Hauptproblem, wenn mehrere Threads auf den gemeinsamen Speicher zugreifen, was manchmal zu Fehlern führt, um zu vermeiden, dass ein Thread von einem anderen Thread übersehen wird, wenn er ausfällt.
  2. Datenintegrität
  3. Mit einer gemeinsam genutzten Ressource zu arbeiten, die in der realen Welt, wie z. B. in Bankensystemen, sehr wichtig ist.

Hinweis: Verwenden Sie das Schlüsselwort „synced“ nur, wenn es am dringendsten benötigt wird. Denken Sie daran, da es keine Prioritätseinstellungen für Threads gibt. Wenn also der Haupt-Thread vor oder nach einem anderen Thread ausgeführt wird, ist die Ausgabe des Programms unterschiedlich.

Der größte Vorteil der Synchronisation ist die Erhöhung des idiotischen Widerstands, da man nicht willkürlich ein Objekt zum Sperren auswählen kann, da String-Literale nicht gesperrt werden können oder der Inhalt sein können. Daher können diese schlechten Praktiken nicht auf einem synchronisierten Methodenblock durchgeführt werden.

Wie wir enorme Vorteile gesehen haben und wissen, wie wichtig es ist, bringt es Nachteile mit sich.

Nachteil: Es treten Performance-Probleme auf, da während der Ausführung eines Threads alle anderen Threads in einen blockierenden Zustand versetzt werden und bemerken, dass sie sich nicht im Wartezustand befinden . Dies führt zu einem Leistungsabfall, wenn die Zeit, die für einen Thread benötigt wird, zu lang ist.

Count-Variable-Shared-Resource

Wie aus dem Bild ersichtlich, in dem wir diese Zählvariable als gemeinsam genutzte Ressource erhalten, wird sie zufällig aktualisiert. Aufgrund von Multithreading wird dieses Konzept zu einer Notwendigkeit.

  • Fall 1: Wenn „ Haupt-Thread“ zuerst ausgeführt wird, wird der Zählerstand inkrementiert, gefolgt von einem „ Thread T“ in der Synchronisation
  • Fall 2: Wenn ' Thread T ' zuerst ausgeführt wird, wird der Zähler nicht erhöht, gefolgt von ' Main Thread ' in der Synchronisation

Implementierung: Nehmen wir ein Beispielprogramm, um diesen 0 1 Zählkonflikt zu beobachten

Beispiel:

Java

// Java Program to illustrate Output Conflict between
// Execution of Main thread vs Thread created
 
// count = 1 if main thread executes first
// count = 1 if created thread executes first
 
// Importing basic required libraries
import java.io.*;
import java.util.*;
 
// Class 1
// Helper Class extending Thread class
class MyThread extends Thread {
 
    // Declaring and initializing initial count to zero
    int count = 0;
 
    // Method 1
    // To increment the count above by unity
    void increment() { count++; }
 
    // Method 2
    // run method for thread invoked after
    // created thread has started
    public void run()
    {
 
        // Call method in this method
        increment();
 
        // Print and display the count
        System.out.println("Count : " + count);
    }
}
 
// Class 2
public class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
        // Creating the above our Thread class object
        // in the main() method
        MyThread t1 = new MyThread();
 
        // start() method to start executio of created
        // thread that will look for run() method
        t1.start();
    }
}

 
 

Ausgabe:

Erklärung der Ausgabe:

Hier wird der Zähler auf 1 erhöht, was bedeutet, dass „ Haupt -Thread “ vor „ erstelltem Thread “ ausgeführt wurde. Wir haben es viele Male ausgeführt und kompiliert und erneut ausgeführt, wobei der Hauptthread hier in allen Fällen schneller ausgeführt wird als der erstellte Thread, aber denken Sie daran, dass die Ausgabe variieren kann. Unser erstellter Thread kann vor dem „ Hauptthread “ ausgeführt werden, was zu „Count: 0“ als Ausgabe auf der Konsole führt. 

Nun, ein weiteres Thema, das im Umgang mit der Synchronisation in Threads auftaucht, ist Thread-Sicherheit in der Java- Synchronisation ist das neue Konzept, das bei der Synchronisation entsteht, also lassen Sie es uns nachdenklich diskutieren

  • Ein reales Szenario gefolgt von
  • Bildliche Darstellung als Illustration gefolgt von
  • Technische Beschreibung und Umsetzung

Szenario aus dem wirklichen Leben

Angenommen, eine Person hebt einen bestimmten Geldbetrag von der Bank ab und gleichzeitig führt die mit derselben Kontonummer registrierte ATM-Karte einen Abhebungsvorgang durch einen anderen Benutzer durch. Nehmen wir nun an, dass durch das Abheben eines bestimmten Geldbetrags aus dem Net Banking das Guthaben auf dem Konto geringer wird als der Betrag, der abgehoben werden müsste, oder umgekehrt. Dies macht die Bank unsicher, da mehr Geld vom Konto abgebucht wird, als tatsächlich auf dem Konto vorhanden war, was die Bank sehr unsicher macht und im täglichen Leben nicht sichtbar ist. Was Banken also tun, ist, dass sie jeweils nur eine Transaktion zulassen. Wenn es vorbei ist, ist ein weiteres erlaubt.

Illustration:

Interpretieren der gleichen Technologie, da zwei verschiedene Prozesse ablaufen, deren Objekt im Falle einer parallelen Ausführung von Threads überschrieben wird. Jetzt besitzen solche Eigenschaften über Threads, dass sie vor der Ausführung oder in einfacheren Worten, um sie zu synchronisieren, darauf achten sollten. Dieser Mechanismus wird als Thread Safe bezeichnet, wobei das Schlüsselwort „ synced “ vor der gemeinsamen parallel auszuführenden Methode/Funktion verwendet wird. 

Technische Beschreibung:

Wie wir wissen, hat Java eine Funktion, Multithreading , bei der mehrere Threads gleichzeitig ausgeführt werden. Wenn mehrere Threads an denselben Daten arbeiten und sich der Wert unserer Daten ändert, ist dieses Szenario nicht Thread-sicher und wir erhalten inkonsistente Ergebnisse. Wenn ein Thread bereits an einem Objekt arbeitet und verhindert, dass ein anderer Thread an demselben Objekt arbeitet, wird dieser Prozess als Thread-Sicherheit bezeichnet. Nun gibt es mehrere Möglichkeiten, Thread-Sicherheit in unserem Programm zu erreichen, und zwar wie folgt:

  1. Synchronisierung verwenden
  2. Verwenden des flüchtigen Schlüsselworts
  3. Atomare Variable verwenden
  4. Endgültiges Schlüsselwort verwenden

Fazit: Wenn wir also auf jeweils einen Thread zugreifen, können wir von einem Thread-sicheren Programm sprechen, und wenn auf mehrere Threads zugegriffen wird, wird das Programm als Thread-unsicher bezeichnet, d. h. eine Ressource nach der anderen kann nicht gemeinsam genutzt werden mehrere Threads gleichzeitig.

Implementierung:

  • Java-Programm zur Veranschaulichung unvollständiger Thread-Iterationen, die den Zählerwert unabhängig von der Iterationsgrenze auf Null zurückgeben
  • Java-Programm zur Veranschaulichung vollständiger Thread-Iterationen zur Veranschaulichung der Methode join()
  • Java-Programm zur Veranschaulichung von Thread-unsicheren oder nicht synchronisierenden Programmen bei unvollständigen Iterationen
  • Java-Programm zur Veranschaulichung von Thread-sicheren und synchronisierten Programmen ab Vollständige Iterationen mit dem Schlüsselwort „synced“.

Beispiele

Java

// Example 1
// Java Program to illustrate Incomplete Thread Iterations
// Returning Counter Value to Zero
// irrespective of iteration bound
 
// Importing input output classes
import java.io.*;
 
// Class 1
// Helper Class
class TickTock {
 
    // Member variable of this class
    int count;
 
    // Method of this Class
    // It increments counter value whenever called
    public void increment()
    {
        // Increment count by unity
        // i.e count = count + 1;
        count++;
    }
    //
}
 
// Class 2
// Synchronization demo class
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args) throws Exception
    {
 
        // Creating an object of class TickTock in main()
        TickTock tt = new TickTock();
 
        // Now, creating an thread object
        // using Runnable interface
        Thread t1 = new Thread(new Runnable() {
            // Method
            // To begin the execution of thread
            public void run()
            {
 
                // Expression
                for (int i = 0; i < 10000; i++) {
 
                    // Calling object of above class
                    // in main() method
                    tt.increment();
                }
            }
        });
 
        // Making above thread created to start
        // via start() method which automatically
        // calls run() method in Ticktock class
        t1.start();
 
        // Print and display the count
        System.out.println("Count : " + tt.count);
    }
}

Java

// Example 2
// Java Program to Illustrate Complete Thread Iterations
// illustrating join() Method
 
// Importing input output classes
import java.io.*;
 
// Class 1
// Helper Class
class TickTock {
 
    // Member variable of this class
    int count;
 
    // Method of this Class
    public void increment()
    {
 
        // Increment count by unity
        // whenever this function is called
        count++;
    }
}
 
// Class 2
// Synchronization demo class
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args) throws Exception
    {
 
        // Creating an object of class TickTock in main()
        TickTock tt = new TickTock();
 
        // Now, creating an thread object
        // using Runnable interface
        Thread t1 = new Thread(new Runnable() {
            // Method
            // To begin the execution of thread
            public void run()
            {
 
                // Expression
                for (int i = 0; i < 1000; i++) {
 
                    // Calling object of above class
                    // in main() method
                    tt.increment();
                }
            }
        });
 
        // Making above thread created to start
        // via start() method which automatically
        // calls run() method
        t1.start();
 
        // Now we are making main() thread to wait so
        // that thread t1 completes it job
        // using join() method
        t1.join();
 
        // Print and display the count value
        System.out.println("Count : " + tt.count);
    }
}

Java

// Example 3
// Java Program to Illustrate Thread Unsafe Or
// Non-synchronizing Programs as of Incomplete Iteations
// Without using 'synchronized' program
 
// Importing input output classes
import java.io.*;
 
// Class 1
// Helper Class
class TickTock {
 
    // Member variable of this class
    int count;
 
    // Method of this Class
    public void increment()
    {
 
        // Increment count by unity
        count++;
    }
}
 
// Class 2
// Synchronization demo class
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args) throws Exception
    {
 
        // Creating an object of class TickTock in main()
        TickTock tt = new TickTock();
 
        // Now, creating an thread object
        // using Runnable interface
        Thread t1 = new Thread(new Runnable() {
            // Method
            // To begin the execution of thread
            public void run()
            {
 
                // Expression
                for (int i = 0; i < 100000; i++) {
 
                    // Calling object of above class
                    // in main() method
                    tt.increment();
                }
            }
        });
 
        // Now creating another thread and lets check
        // how they increment count value running parallely
        // Thread 2
        Thread t2 = new Thread(new Runnable() {
            // Method
            // To begin the execution of thread
            public void run()
            {
 
                // Expression
                for (int i = 0; i < 100000; i++) {
 
                    // Calling object of above class
                    // in main() method
                    tt.increment();
                }
            }
        });
 
        // Making above thread created to start
        // via start() method which automatically
        // calls run() method
        t1.start();
        t2.start();
 
        // Now we are making main() thread to wait so
        // that thread t1 completes it job
        t1.join();
        t2.join();
 
        // Print and display the count
        System.out.println("Count : " + tt.count);
    }
}

Java

// Example 4
// Java Program to Illustrate Thread Safe And
// Synchronized Programs as of Complete Iteations
// using 'synchronized' Keyword
 
// Importing input output classes
import java.io.*;
 
// Class 1
// helper Class
class TickTock {
 
    // Member variable of this class
    int count;
 
    // Method of this Class
    public synchronized void increment()
    {
 
        // Increment count by unity
        count++;
    }
    //
}
 
// Class 2
// Synchronization demo class
// Main Class
class GFG {
 
    // Main driver method
    public static void main(String[] args) throws Exception
    {
 
        // Creating an object of class TickTock in main()
        TickTock tt = new TickTock();
 
        // Now, creating an thread object
        // using Runnable interface
        Thread t1 = new Thread(new Runnable() {
            // Method
            // To begin the execution of thread
            public void run()
            {
 
                // Expression
                for (int i = 0; i < 100000; i++) {
 
                    // Calling object of above class
                    // in main() method
                    tt.increment();
                }
            }
        });
 
        // Thread 2
        Thread t2 = new Thread(new Runnable() {
            // Method
            // To begin the execution of thread
            public void run()
            {
 
                // Expression
                for (int i = 0; i < 100000; i++) {
 
                    // Calling object of above class
                    // in main() method
                    tt.increment();
                }
            }
        });
 
        // Making above thread created to start
        // via start() method which automatically
        // calls run() method
        t1.start();
        t2.start();
 
        // Now we are making main() thread to wait so
        // that thread t1 completes it job
        t1.join();
        t2.join();
 
        // Print and display the count
        System.out.println("Count : " + tt.count);
    }
}

 
 

Ausgabe: 

Fall 1

Count : 0

Fall 2

Count : 10000

Fall 3

Count : 151138

Fall 4

Count : 200000

Erklärung der Ausgabe:

In Fall 1 können wir sehen, dass die Anzahl bei der Initialisierung Null ist. Jetzt haben wir zwei Threads Hauptthread und den Thread t1. Es gibt also zwei Threads, also wird das, was manchmal passiert, von beiden Threads geteilt. 

In Fall 1 greifen beide auf die count-Variable zu, wo wir direkt versuchen, über den Thread t1.count auf den Thread zuzugreifen, der immer 0 ausgibt, da wir ihn mit Hilfe des Objekts aufrufen müssen, um die Ausführung durchzuführen.

Jetzt haben wir verstanden, dass die Funktionsweise der Synchronisation ein Thread ist, der in Java nur als Begriff Parallelität bezeichnet wird, der in Laiensprache mehrere Aufgaben ausführt. Lassen Sie uns die Nebenläufigkeit in Threads mit Hilfe einer bildlichen Darstellung darstellen.

Stellen Sie sich die Aufgabe vor, ein Array von Elementen mit einem Multiplikator von 2 zu multiplizieren. Wenn wir nun beginnen, jedes Element zufällig zu multiplizieren, wird dies eine Menge Zeit in Anspruch nehmen, da jedes Mal das Element durchsucht und vom Computer durchsucht wird. Bei weitem haben wir Multithreading oben studiert, in dem wir zu einer einzigen Zeile geschlussfolgert haben, dass Thread das Rückgrat von Multithreading ist. Wenn wir also Threads in die obige Situation einbeziehen, da die Maschine Quad-Core ist, nehmen wir hier 4 Threads für jeden Kern, wobei wir den obigen Rechenbeispielsatz auf (1/4) teilen, was zu einer 4- mal schnelleren Rechenleistung führt. Wenn es im obigen Szenario 4 Sekunden gedauert hat, dauert es jetzt nur noch 1 Sekunde. Dieser Mechanismus parallel laufender Threads, um schnellere und verzögerungsfreie Berechnungen zu erreichen, wird als Nebenläufigkeit bezeichnet.

Hinweis: Entscheiden Sie sich für Multithreading immer für die gleichzeitige Ausführung, und wenn Sie dieses Konzept nicht verwenden, entscheiden Sie sich für die sequentielle Ausführung, obwohl Sie größere Codeblöcke haben, da die Sicherheit unseres Codes das Hauptproblem ist.