Multithreading in Java
Οποιαδήποτε εφαρμογή μπορεί να έχει πολλαπλές διεργασίες (στιγμιότυπα). Κάθε μία από αυτή τη διαδικασία μπορεί να αντιστοιχιστεί είτε ως ένα νήμα είτε ως πολλαπλά νήματα. Θα δούμε σε αυτό το σεμινάριο πώς να εκτελούμε πολλές εργασίες ταυτόχρονα και θα μάθουμε επίσης περισσότερα για τα νήματα και τον συγχρονισμό μεταξύ των νημάτων.
Τι είναι το Single Thread;
Ένα μόνο νήμα μέσα Java είναι βασικά μια ελαφριά και η μικρότερη μονάδα επεξεργασίας. Java χρησιμοποιεί νήματα χρησιμοποιώντας μια «Κλάση Νημάτων». Υπάρχουν δύο τύποι νημάτων - νήμα χρήστη και νήμα δαίμονας (τα νήματα daemon χρησιμοποιούνται όταν θέλουμε να καθαρίσουμε την εφαρμογή και χρησιμοποιούνται στο παρασκήνιο). Όταν ξεκινά μια εφαρμογή για πρώτη φορά, δημιουργείται νήμα χρήστη. Αναρτήστε το, μπορούμε να δημιουργήσουμε πολλά νήματα χρηστών και νήματα δαίμονα.
Παράδειγμα μεμονωμένου νήματος:
package demotest;
public class GuruThread
{
public static void main(String[] args) {
System.out.println("Single Thread");
}
}
Πλεονεκτήματα του απλού νήματος:
- Μειώνει την επιβάρυνση της εφαρμογής καθώς εκτελείται ένα νήμα στο σύστημα
- Επίσης, μειώνει το κόστος συντήρησης της εφαρμογής.
Τι είναι το Multithreading μέσα Java?
Πολλαπλών νημάτων in Java είναι μια διαδικασία εκτέλεσης δύο ή περισσότερων νημάτων ταυτόχρονα για τη μέγιστη χρήση της CPU. Οι εφαρμογές πολλαπλών νημάτων εκτελούν δύο ή περισσότερα νήματα που εκτελούνται ταυτόχρονα. Ως εκ τούτου, είναι επίσης γνωστό ως Concurrency in Java. Κάθε νήμα τρέχει παράλληλα μεταξύ τους. Τα πολλαπλά νήματα δεν εκχωρούν ξεχωριστή περιοχή μνήμης, επομένως εξοικονομούν μνήμη. Επίσης, η εναλλαγή περιβάλλοντος μεταξύ των νημάτων απαιτεί λιγότερο χρόνο.
Παράδειγμα πολλαπλών νημάτων:
package demotest;
public class GuruThread1 implements Runnable
{
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Thread names are following:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
}
}
Πλεονεκτήματα του multithread:
- Οι χρήστες δεν είναι αποκλεισμένοι επειδή τα νήματα είναι ανεξάρτητα και μπορούμε να εκτελέσουμε πολλές λειτουργίες κατά καιρούς
- Ως εκ τούτου, τα νήματα είναι ανεξάρτητα, τα άλλα νήματα δεν θα επηρεαστούν εάν ένα νήμα πληροί μια εξαίρεση.
Κύκλος ζωής νήματος σε Java
Ο κύκλος ζωής ενός νήματος:

Υπάρχουν διάφορα στάδια του κύκλου ζωής του νήματος όπως φαίνεται στο παραπάνω διάγραμμα:
- Νέα
- Δυνατότητα εκτέλεσης
- Τρέξιμο
- Αναμονή
- Νεκρός
- Νέα: Σε αυτή τη φάση, το νήμα δημιουργείται χρησιμοποιώντας την κλάση "Thread class". Παραμένει σε αυτήν την κατάσταση μέχρι το πρόγραμμα ξεκινά το νήμα. Είναι επίσης γνωστό ως γεννημένο νήμα.
- Δυνατότητα εκτέλεσης: Σε αυτή τη σελίδα, το στιγμιότυπο του νήματος καλείται με μια μέθοδο έναρξης. Ο έλεγχος νήματος δίνεται στον προγραμματιστή για να ολοκληρώσει την εκτέλεση. Εξαρτάται από τον προγραμματιστή, αν θα τρέξει το νήμα.
- Τρέξιμο: Όταν το νήμα αρχίσει να εκτελείται, τότε η κατάσταση αλλάζει σε κατάσταση "τρέχοντας". Ο χρονοπρογραμματιστής επιλέγει ένα νήμα από το σύνολο νημάτων και αρχίζει να εκτελείται στην εφαρμογή.
- Αναμονή: Αυτή είναι η κατάσταση όταν ένα νήμα πρέπει να περιμένει. Καθώς υπάρχουν πολλά νήματα που εκτελούνται στην εφαρμογή, υπάρχει ανάγκη για συγχρονισμό μεταξύ των νημάτων. Ως εκ τούτου, ένα νήμα πρέπει να περιμένει, μέχρι να εκτελεστεί το άλλο νήμα. Επομένως, αυτή η κατάσταση αναφέρεται ως κατάσταση αναμονής.
- Νεκρός: Αυτή είναι η κατάσταση όταν το νήμα τερματίζεται. Το νήμα είναι σε κατάσταση λειτουργίας και μόλις ολοκληρώθηκε η επεξεργασία βρίσκεται σε "νεκρή κατάσταση".
Μέθοδοι πολλαπλών νημάτων σε Java
Μερικές από τις μεθόδους που χρησιμοποιούνται συνήθως για νήματα είναι:| Μέθοδος | Περιγραφή |
|---|---|
| αρχή() | Αυτή η μέθοδος ξεκινά την εκτέλεση του νήματος και FMV καλεί τη μέθοδο run() στο νήμα. |
| Ύπνος (int χιλιοστά του δευτερολέπτου) | Αυτή η μέθοδος κάνει το νήμα να κοιμάται, επομένως η εκτέλεση του νήματος θα σταματήσει για χιλιοστά του δευτερολέπτου που παρέχονται και μετά από αυτό, το νήμα αρχίζει ξανά να εκτελείται. Αυτό βοηθά στο συγχρονισμό των νημάτων. |
| getName () | Επιστρέφει το όνομα του νήματος. |
| setPriority (σε νέα προτεραιότητα) | Αλλάζει την προτεραιότητα του νήματος. |
| απόδοση () | Αναγκάζει το τρέχον νήμα να σταματήσει και άλλα νήματα να εκτελεστούν. |
Παράδειγμα: Σε αυτό το πρόγραμμα πολλαπλών νημάτων στο Java Για παράδειγμα, θα δημιουργήσουμε ένα νήμα και θα εξερευνήσουμε ενσωματωμένες μεθόδους που είναι διαθέσιμες για νήματα.
package demotest;
public class thread_example1 implements Runnable {
@Override
public void run() {
}
public static void main(String[] args) {
Thread guruthread1 = new Thread();
guruthread1.start();
try {
guruthread1.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
guruthread1.setPriority(1);
int gurupriority = guruthread1.getPriority();
System.out.println(gurupriority);
System.out.println("Thread Running");
}
}
Επεξήγηση του κώδικα:
- Code Γραμμή 2: Δημιουργούμε μια κλάση "thread_Example1" που υλοποιεί τη διεπαφή Runnable (θα πρέπει να υλοποιηθεί από οποιαδήποτε κλάση οι παρουσίες της οποίας προορίζονται να εκτελεστούν από το νήμα.)
- Code Γραμμή 4: Αντικαθιστά τη μέθοδο εκτέλεσης της διεπαφής με δυνατότητα εκτέλεσης, καθώς είναι υποχρεωτική η παράκαμψη αυτής της μεθόδου
- Code Γραμμή 6: Εδώ έχουμε ορίσει την κύρια μέθοδο με την οποία θα ξεκινήσουμε την εκτέλεση του νήματος.
- Code Γραμμή 7: Εδώ δημιουργούμε ένα νέο όνομα νήματος ως "guruthread1" εγκαινιάζοντας μια νέα κατηγορία νήματος.
- Code Γραμμή 8: θα χρησιμοποιήσουμε τη μέθοδο "start" του νήματος χρησιμοποιώντας την περίπτωση "guruthread1". Εδώ το νήμα θα ξεκινήσει να εκτελείται.
- Code Γραμμή 10: Εδώ χρησιμοποιούμε τη μέθοδο "sleep" του νήματος χρησιμοποιώντας το παράδειγμα "guruthread1". Ως εκ τούτου, το νήμα θα κοιμάται για 1000 χιλιοστά του δευτερολέπτου.
- Code 9-14: Εδώ έχουμε βάλει τη μέθοδο ύπνου στο μπλοκ try catch καθώς υπάρχει επιλεγμένη εξαίρεση που συμβαίνει, π.χ. Διακεκομμένη εξαίρεση.
- Code Γραμμή 15: Εδώ ορίζουμε την προτεραιότητα του νήματος στο 1 από όποια προτεραιότητα ήταν
- Code Γραμμή 16: Εδώ παίρνουμε την προτεραιότητα του νήματος χρησιμοποιώντας την getPriority()
- Code Γραμμή 17: Εδώ εκτυπώνουμε την τιμή που ανακτήθηκε από το getPriority
- Code Γραμμή 18: Εδώ γράφουμε ένα κείμενο που τρέχει το νήμα.
Όταν εκτελείτε τον παραπάνω κώδικα, λαμβάνετε την ακόλουθη έξοδο:
Παραγωγή:
Το 5 είναι η προτεραιότητα του νήματος και το Thread Running είναι το κείμενο που είναι η έξοδος του κώδικά μας.
Java Νήμα Syncχρονισμός
Στο multithreading υπάρχει η ασύγχρονη συμπεριφορά των προγραμμάτων. Εάν ένα νήμα εγγράφει ορισμένα δεδομένα και ένα άλλο νήμα που διαβάζει δεδομένα ταυτόχρονα, μπορεί να δημιουργήσει ασυνέπεια στην εφαρμογή. Όταν υπάρχει ανάγκη πρόσβασης στους κοινόχρηστους πόρους από δύο ή περισσότερα νήματα, τότε χρησιμοποιείται η προσέγγιση συγχρονισμού. Java έχει παράσχει συγχρονισμένες μεθόδους για την εφαρμογή συγχρονισμένης συμπεριφοράς.
Σε αυτήν την προσέγγιση, μόλις το νήμα φτάσει μέσα στο συγχρονισμένο μπλοκ, τότε κανένα άλλο νήμα δεν μπορεί να καλέσει αυτήν τη μέθοδο στο ίδιο αντικείμενο. Όλα τα νήματα πρέπει να περιμένουν έως ότου αυτό το νήμα ολοκληρώσει το συγχρονισμένο μπλοκ και βγει από αυτό. Με αυτόν τον τρόπο, ο συγχρονισμός βοηθά σε μια εφαρμογή πολλαπλών νημάτων. Ένα νήμα πρέπει να περιμένει έως ότου το άλλο νήμα ολοκληρώσει την εκτέλεσή του μόνο τότε επιτρέπεται να εκτελεστούν τα άλλα νήματα.
Μπορεί να γραφτεί με την ακόλουθη μορφή:
Synchronized(object)
{
//Block of statements to be synchronized
}
Multithreading in Java Παραδείγματα προγραμμάτων
Σε αυτή την πολυνηματική Java Για παράδειγμα, θα πάρουμε δύο νήματα και θα φέρουμε τα ονόματα του νήματος.
Παράδειγμα 1:
GuruThread1.java
package demotest;
public class GuruThread1 implements Runnable{
/**
* @param args
*/
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Thread names are following:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
}
}
Επεξήγηση του κώδικα:
- Code Γραμμή 3: Έχουμε παρακολουθήσει ένα μάθημα»GuruThread1” που υλοποιεί το Runnable (θα πρέπει να υλοποιείται από οποιαδήποτε κλάση της οποίας οι παρουσίες προορίζονται να εκτελεστούν από το νήμα.)
- Code Γραμμή 8: Αυτή είναι η κύρια μέθοδος της τάξης
- Code Γραμμή 9: Εδώ δημιουργούμε την κλάση Thread και δημιουργούμε ένα στιγμιότυπο με το όνομα "guruThread1" και δημιουργούμε ένα νήμα.
- Code Γραμμή 10: Εδώ δημιουργούμε την κλάση Thread και δημιουργούμε ένα στιγμιότυπο με το όνομα "guruThread2" και δημιουργούμε ένα νήμα.
- Code Γραμμή 11: Ξεκινάμε το νήμα, π.χ. guruThread1.
- Code Γραμμή 12: Ξεκινάμε το νήμα, π.χ. guruThread2.
- Code Γραμμή 13: Εξαγωγή του κειμένου ως "Τα ονόματα των νημάτων είναι τα ακόλουθα:"
- Code Γραμμή 14: Λήψη του ονόματος του νήματος 1 χρησιμοποιώντας τη μέθοδο getName() της κλάσης νήματος.
- Code Γραμμή 15: Λήψη του ονόματος του νήματος 2 χρησιμοποιώντας τη μέθοδο getName() της κλάσης νήματος.
Όταν εκτελείτε τον παραπάνω κώδικα, λαμβάνετε την ακόλουθη έξοδο:
Παραγωγή:
Τα ονόματα των νημάτων εμφανίζονται εδώ ως
- Guru1
- Guru2
Παράδειγμα 2:
Σε αυτό το πολυνηματικό σε Java Για παράδειγμα, θα μάθουμε για τις μεθόδους παράκαμψης run() και start() μιας διεπαφής με δυνατότητα εκτέλεσης και θα δημιουργήσουμε δύο νήματα αυτής της κλάσης και θα τα εκτελέσουμε ανάλογα.
Επίσης, παρακολουθούμε δύο μαθήματα,
- Ένα που θα υλοποιήσει τη διεπαφή με δυνατότητα εκτέλεσης και
- Ένα άλλο που θα έχει την κύρια μέθοδο και θα εκτελείται ανάλογα.
package demotest;
public class GuruThread2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
GuruThread3 threadguru1 = new GuruThread3("guru1");
threadguru1.start();
GuruThread3 threadguru2 = new GuruThread3("guru2");
threadguru2.start();
}
}
class GuruThread3 implements Runnable {
Thread guruthread;
private String guruname;
GuruThread3(String name) {
guruname = name;
}
@Override
public void run() {
System.out.println("Thread running" + guruname);
for (int i = 0; i < 4; i++) {
System.out.println(i);
System.out.println(guruname);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread has been interrupted");
}
}
}
public void start() {
System.out.println("Thread started");
if (guruthread == null) {
guruthread = new Thread(this, guruname);
guruthread.start();
}
}
}
Επεξήγηση του κώδικα:
- Code Γραμμή 2: Εδώ κάνουμε μάθημα»GuruThread2” το οποίο θα περιέχει τη μέθοδο main.
- Code Γραμμή 4: Εδώ παίρνουμε μια κύρια μέθοδο της τάξης.
- Code Γραμμή 6-7: Εδώ δημιουργούμε μια παρουσία της κλάσης GuruΤο Thread3 (το οποίο δημιουργείται στις παρακάτω γραμμές του κώδικα) ως "threadguru1" και ξεκινάμε το νήμα.
- Code Γραμμή 8-9: Εδώ δημιουργούμε μια άλλη παρουσία της κλάσης GuruΤο Thread3 (το οποίο δημιουργείται στις παρακάτω γραμμές του κώδικα) ως "threadguru2" και ξεκινάμε το νήμα.
- Code Γραμμή 11: Εδώ δημιουργούμε μια κλάση "GuruThread3” το οποίο υλοποιεί την εκτελέσιμη διεπαφή (θα πρέπει να υλοποιείται από οποιαδήποτε κλάση της οποίας οι παρουσίες προορίζονται να εκτελεστούν από το νήμα.)
- Code Γραμμή 13-14: Παίρνουμε δύο μεταβλητές κλάσης από τις οποίες η μία είναι της κλάσης τύπου thread και η άλλη της κλάσης string.
- Code Γραμμή 15-18: υπερισχύουμε του GuruΚατασκευαστής Thread3, ο οποίος δέχεται ένα όρισμα ως τύπο συμβολοσειράς (που είναι το όνομα του νήματος) που αντιστοιχίζεται στη μεταβλητή κλάσης guruname και επομένως αποθηκεύεται το όνομα του νήματος.
- Code Γραμμή 20: Εδώ παρακάμπτουμε τη μέθοδο run() της διεπαφής με δυνατότητα εκτέλεσης.
- Code Γραμμή 21: Εξάγουμε το όνομα του νήματος χρησιμοποιώντας την πρόταση println.
- Code Γραμμή 22-31: Εδώ χρησιμοποιούμε έναν βρόχο for με μετρητή αρχικοποιημένο στο 0, και δεν πρέπει να είναι μικρότερος από 4 (μπορούμε να πάρουμε οποιονδήποτε αριθμό, επομένως εδώ ο βρόχος θα τρέξει 4 φορές) και αυξάνοντας τον μετρητή. Εκτυπώνουμε το όνομα του νήματος και επίσης κάνουμε το νήμα να αδράνει για 1000 χιλιοστά του δευτερολέπτου μέσα σε ένα μπλοκ try-catch καθώς η μέθοδος ύπνου αυξάνει την επιλεγμένη εξαίρεση.
- Code Γραμμή 33: Εδώ παρακάμπτουμε τη μέθοδο έναρξης της διεπαφής με δυνατότητα εκτέλεσης.
- Code Γραμμή 35: Βγάζουμε το κείμενο "Το νήμα ξεκίνησε".
- Code Γραμμή 36-40: Εδώ παίρνουμε μια συνθήκη if για να ελέγξουμε αν η μεταβλητή κλάσης guruthread έχει αξία ή όχι. Εάν είναι μηδενικό, τότε δημιουργούμε ένα στιγμιότυπο χρησιμοποιώντας κλάση νήματος που παίρνει το όνομα ως παράμετρο (τιμή για την οποία έχει εκχωρηθεί στον κατασκευαστή). Μετά από αυτό το νήμα ξεκινά χρησιμοποιώντας τη μέθοδο start().
Όταν εκτελείτε τον παραπάνω κώδικα, λαμβάνετε την ακόλουθη έξοδο:
Παραγωγή:
Υπάρχουν δύο νήματα, επομένως, λαμβάνουμε δύο φορές το μήνυμα "Το νήμα ξεκίνησε".
Παίρνουμε τα ονόματα του νήματος όπως τα έχουμε βγάλει.
Μπαίνει στον βρόχο for όπου εκτυπώνουμε το όνομα του μετρητή και του νήματος και ο μετρητής ξεκινά με 0.
Ο βρόχος εκτελείται τρεις φορές και ενδιάμεσα το νήμα αδράνει για 1000 χιλιοστά του δευτερολέπτου.
Ως εκ τούτου, πρώτα, παίρνουμε guru1 μετά guru2 και μετά πάλι guru2 επειδή το νήμα κοιμάται εδώ για 1000 χιλιοστά του δευτερολέπτου και μετά τον επόμενο guru1 και ξανά τον guru1, το νήμα κοιμάται για 1000 χιλιοστά του δευτερολέπτου, οπότε παίρνουμε τον guru2 και μετά τον guru1.
Περίληψη
Σε αυτό το σεμινάριο, είδαμε εφαρμογές πολλαπλών νημάτων Java και πώς να χρησιμοποιήσετε το single και το multi thread in Java.
- Εξηγήστε το multithreading in Java: στο multithreading, οι χρήστες δεν αποκλείονται καθώς τα νήματα είναι ανεξάρτητα και μπορούν να εκτελούν πολλαπλές λειτουργίες ταυτόχρονα
- Τα διάφορα στάδια του κύκλου ζωής του νήματος είναι,
- Νέα
- Δυνατότητα εκτέλεσης
- Τρέξιμο
- Αναμονή
- Νεκρός
- Μάθαμε και για συγχρονισμός μεταξύ νημάτων, που βοηθούν την εφαρμογή να λειτουργεί ομαλά.
- Προγραμματισμός πολλαπλών νημάτων σε Java διευκολύνει πολλές περισσότερες εργασίες εφαρμογής.



