JavaRush /Java Blogu /Random-AZ /Java-da multithreading: mahiyyət, üstünlüklər və ümumi tə...

Java-da multithreading: mahiyyət, üstünlüklər və ümumi tələlər

Qrupda dərc edilmişdir
Salam! İlk öncə sizi təbrik edirik: Java-da Multithreading mövzusuna çatdınız! Bu, ciddi nailiyyətdir, qarşıda çox uzun yol var. Ancaq hazır olun: bu kursun ən çətin mövzularından biridir. Məsələ onda deyil ki, burada mürəkkəb siniflər və ya bir çox metodlardan istifadə olunur: əksinə, hətta iki onlarla da yoxdur. Daha çox düşüncənizi bir az dəyişmək lazımdır. Əvvəllər proqramlarınız ardıcıllıqla icra olunurdu. Bəzi kod sətirləri digərlərini izlədi, bəzi üsullar digərlərini izlədi və ümumilikdə hər şey aydın idi. Əvvəlcə bir şey hesablayın, sonra nəticəni konsolda göstərin, sonra proqramı dayandırın. Çox iş parçacığını başa düşmək üçün paralellik baxımından düşünmək daha yaxşıdır. Çox sadə bir şeylə başlayaq :) Java-da multithreading: mahiyyət, üstünlüklər və ümumi tələlər - 1Təsəvvür edin ki, ailəniz bir evdən digərinə köçür. Hərəkətin vacib hissəsi kitablarınızı qablaşdırmaqdır. Siz çoxlu kitab topladınız və onları qutulara qoymaq lazımdır. İndi yalnız sən azadsan. Ana yemək hazırlayır, qardaş paltar yığır, bacı isə mağazaya getdi. Heç olmasa təkbaşına idarə edə bilərsən və gec-tez tapşırığı özün də tamamlayacaqsan, lakin bu, çox vaxt aparacaq. Ancaq 20 dəqiqədən sonra bacınız mağazadan qayıdacaq və onun başqa işi yoxdur. Beləliklə, o sizə qoşula bilər. Tapşırıq eyni qaldı: kitabları qutulara qoyun. Sadəcə iki dəfə sürətli işləyir. Niyə? Çünki işlər paralel şəkildə aparılır. İki fərqli "ip" (siz və bacınız) eyni vaxtda eyni tapşırığı yerinə yetirirsiniz və heç bir şey dəyişməzsə, hər şeyi tək edəcəyiniz vəziyyətlə müqayisədə vaxt fərqi çox böyük olacaq. Qardaşınız tapşırığını tezliklə başa çatdırsa, sizə kömək edə bilər və işlər daha da sürətlə gedəcək.

Java-da multithreading həll etdiyi problemlər

Əslində, Java multithreading iki əsas problemi həll etmək üçün icad edilmişdir:
  1. Eyni anda bir neçə hərəkəti yerinə yetirin.

    Yuxarıdakı nümunədə müxtəlif iplər (yəni ailə üzvləri) paralel olaraq bir neçə hərəkət etdi: qabları yudu, mağazaya getdi, əşyaları qatladı.

    Daha çox “proqramçı” nümunəsi verilə bilər. Təsəvvür edin ki, istifadəçi interfeysi olan bir proqramınız var. Davam et düyməsini sıxdıqda proqram daxilində bəzi hesablamalar baş verməli və istifadəçi aşağıdakı interfeys ekranını görməlidir. Bu hərəkətlər ardıcıl olaraq həyata keçirilirsə, "Davam et" düyməsini basdıqdan sonra proqram sadəcə dondurulacaq. İstifadəçi bütün daxili hesablamalar tamamlanana və proqram interfeysin çəkilməyə başlayacağı hissəyə çatana qədər “Davam et” düyməsi ilə eyni ekranı görəcək.

    Yaxşı, bir neçə dəqiqə gözləyək!

    Java-da multithreading: mahiyyət, üstünlüklər və ümumi tələlər - 3

    Biz həmçinin proqramımızı yenidən düzəldə və ya proqramçıların dediyi kimi “paralelləşdirə” bilərik. Lazımi hesablamalar bir ipdə aparılsın, digərində isə interfeys göstərilsin. Əksər kompüterlərdə bunun üçün kifayət qədər resurs var. Bu vəziyyətdə, proqram "axmaq" olmayacaq və istifadəçi içəridə baş verənlərdən narahat olmadan interfeys ekranları arasında sakitcə hərəkət edəcək. qarışmır :)

  2. Hesablamaları sürətləndirin.

    Burada hər şey daha sadədir. Əgər prosessorumuz bir neçə nüvəyə malikdirsə və əksər prosessorlar indi çoxnüvəlidirsə, tapşırıqlarımızın siyahısı bir neçə nüvə ilə paralel olaraq həll edilə bilər. Aydındır ki, əgər bizə 1000 problemi həll etmək lazımdırsa və onların hər biri bir saniyədə həll edilərsə, bir nüvə 1000 saniyəyə, iki nüvə 500 saniyəyə, üç nüvə 333 saniyədən bir az çox müddətdə siyahının öhdəsindən gələcək və s.

Lakin, artıq mühazirədə oxuduğunuz kimi, müasir sistemlər çox ağıllıdır və hətta bir hesablama nüvəsində tapşırıqlar növbə ilə yerinə yetirildikdə paralellik və ya psevdoparalelliyi həyata keçirə bilirlər. Gəlin ümumi şeylərdən konkretlərə keçək və Java kitabxanasında multithreading ilə bağlı əsas siniflə - java.lang.Thread ilə tanış olaq. Düzünü desək, Java-da mövzular sinif nümunələri ilə təmsil olunur Thread. Yəni 10 mövzu yaratmaq və işlətmək üçün bu sinifin 10 obyektinə ehtiyacınız olacaq. Ən sadə nümunəni yazaq:
public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("I'm Thread! My name is " + getName());
   }
}
Mövzular yaratmaq və işə salmaq üçün bir sinif yaratmalı və onu java.lang. Threadvə içindəki metodu ləğv edin run(). Sonuncu çox vacibdir. Məhz metodda run()ipimizin icra etməli olduğu məntiqi təyin edirik. İndi bir nümunə yaradıb MyFirstThreadonu işə salsaq, üsul run()konsolda öz adı ilə bir sətir çap edəcək: metod getName()avtomatik olaraq təyin olunan ipin “sistem” adını çap edir. Baxmayaraq ki, əslində niyə “əgər”? Yaradaq və sınaqdan keçirək!
public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Konsol çıxışı: I'm Thread! Mənim adım Thread-2 I'm Thread! Mənim adım Thread-1 I'm Thread! Mənim adım Thread-0 I'm Thread! Mənim adım Thread-3 I'm Thread! Mənim adım Thread-6 I'm Thread! Mənim adım Thread-7 I'm Thread! Mənim adım Thread-4 I'm Thread! Mənim adım Thread-5 I'm Thread! Mənim adım Thread-9 I'm Thread! Mənim adım Thread-8MyFirstThread Biz miras qalan 10 mövzu (obyekt) yaradırıq Threadvə obyektin metodunu çağıraraq onları işə salırıq start(). Metod çağırıldıqdan sonra start()onun metodu işə başlayır run()və orada yazılmış məntiq icra olunur. Diqqət edin: mövzu adları qaydasında deyil. Olduqca qəribədir, niyə onlar növbə ilə edam olunmayıb: Thread-0, Thread-1, Thread-2və s. Bu, standart, “ardıcıl” düşüncənin işləməyəcəyinə tam bir nümunədir. Fakt budur ki, bu halda biz yalnız 10 mövzu yaratmaq və işə salmaq üçün əmrlər veririk. Onların hansı ardıcıllıqla işə salınması mövzu planlayıcısı tərəfindən müəyyən edilir: əməliyyat sisteminin daxilində xüsusi mexanizm. Onun necə strukturlaşdırıldığı və hansı prinsip əsasında qərarlar qəbul etdiyi çox mürəkkəb bir mövzudur və biz indi buna dalmayacağıq. Xatırlamaq lazım olan əsas şey proqramçının mövzunun icrası ardıcıllığına nəzarət edə bilməməsidir. Vəziyyətin ciddiliyini dərk etmək üçün main()yuxarıdakı nümunədəki metodu bir neçə dəfə daha işlətməyə çalışın. İkinci konsol çıxışı: I'm Thread! Mənim adım Thread-0 I'm Thread! Mənim adım Thread-4 I'm Thread! Mənim adım Thread-3 I'm Thread! Mənim adım Thread-2 I'm Thread! Mənim adım Thread-1 I'm Thread! Mənim adım Thread-5 I'm Thread! Mənim adım Thread-6 I'm Thread! Mənim adım Thread-8 I'm Thread! Mənim adım Thread-9 I'm Thread! Mənim adım Thread-7 Üçüncü konsol çıxışı: I'm Thread! Mənim adım Thread-0 I'm Thread! Mənim adım Thread-3 I'm Thread! Mənim adım Thread-1 I'm Thread! Mənim adım Thread-2 I'm Thread! Mənim adım Thread-6 I'm Thread! Mənim adım Thread-4 I'm Thread! Mənim adım Thread-9 I'm Thread! Mənim adım Thread-5 I'm Thread! Mənim adım Thread-7 I'm Thread! Mənim adım Thread-8-dir

Çox iş parçacığının yaratdığı problemlər

Kitablarla nümunədə siz çoxilliklərin kifayət qədər vacib problemləri həll etdiyini və onun istifadəsi proqramlarımızın işini sürətləndirdiyini gördünüz. Çox hallarda - dəfələrlə. Ancaq çox iş parçacığının mürəkkəb bir mövzu hesab edilməsi boş yerə deyil. Axı, düzgün istifadə edilmədikdə, onları həll etmək əvəzinə problemlər yaradır. “Problem yaradın” deyəndə mücərrəd bir şeyi nəzərdə tutmuram. Multithreading səbəb ola biləcəyi iki xüsusi problem var: çıxılmaz vəziyyət və yarış vəziyyəti. Deadlock elə bir vəziyyətdir ki, çoxlu mövzular bir-birinin tutduğu resursları gözləyir və onlardan heç biri icra etməyə davam edə bilmir. Gələcək mühazirələrdə bu barədə daha çox danışacağıq, lakin hələlik bu nümunə kifayət edəcək: Java-da multithreading: mahiyyət, üstünlüklər və ümumi tələlər - 4 Təsəvvür edin ki, thread-1 hansısa Obyekt-1 ilə, ip-2 isə Obyekt-2 ilə işləyir. Proqram belə yazılmışdır:
  1. Thread-1 Obyekt-1 ilə işləməyi dayandıracaq və Thread-2 Obyekt 2 ilə işləməyi dayandırıb Obyekt-1-ə keçən kimi Obyekt-2-yə keçəcək.
  2. Thread-1 Obyekt 1 ilə işləməyi dayandırıb Obyekt-2-yə keçən kimi Thread-2 Obyekt-2 ilə işləməyi dayandıracaq və Obyekt-1-ə keçəcək.
Multithreading haqqında dərin biliyi olmasa belə, ondan heç nə gəlməyəcəyini asanlıqla başa düşə bilərsiniz. İplər heç vaxt yerini dəyişməyəcək və bir-birini əbədi gözləyəcək. Səhv açıq görünür, amma əslində belə deyil. Proqrama asanlıqla icazə verə bilərsiniz. Növbəti mühazirələrdə dalana səbəb olan kod nümunələrinə baxacağıq. Yeri gəlmişkən, Quorada çıxılmaz vəziyyətin nə olduğunu izah edən əla real həyat nümunəsi var . “Hindistanın bəzi ştatlarında fermer kimi qeydiyyatdan keçməyincə sizə kənd təsərrüfatı torpaqlarını satmayacaqlar. Ancaq kənd təsərrüfatına yararlı torpaq sahəsi yoxdursa, fermer kimi qeydiyyata düşməyəcəksiniz”. Əla, nə deyə bilərəm! :) İndi yarışın vəziyyəti haqqında - yarışın vəziyyəti. Yarış şərti, sistemin və ya tətbiqin işləməsinin kodun hissələrinin yerinə yetirilmə ardıcıllığından asılı olduğu çox yivli sistem və ya proqramda dizayn qüsurudur. Çalışan mövzularla nümunəni xatırlayın: Java-da multithreading: mahiyyət, üstünlüklər və ümumi tələlər - 5
public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Выполнен поток " + getName());
   }
}

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
İndi təsəvvür edin ki, proqram yemək hazırlayan robotun işinə cavabdehdir! Thread-0 yumurtaları soyuducudan çıxarır. Axın 1 sobanı yandırır. Stream-2 qovurma qabını çıxarıb ocağın üstünə qoyur. Axın 3 sobada od yandırır. Stream 4 tavaya yağ tökün. Stream 5 yumurtaları qırır və tavaya tökür. Stream 6 qabıqları zibil qutusuna atır. Stream-7 hazır omletləri istidən çıxarır. Potok-8 boşqaba omlet qoyur. Stream-9 qabları yuyur. Proqramımızın nəticələrinə baxın: Mövzu-0 yerinə yetirildi Mövzu-2 mövzu icra edildi Mövzu-1 mövzu icra edildi Mövzu-4 mövzu yerinə yetirildi Mövzu-9 mövzu icra edildi Mövzu-5 mövzu icra edildi Mövzu-8 mövzu icra edildi Mövzu-7 mövzu icra edildi Mövzu-7 mövzu icra edildi -3 Mövzu-6 mövzu icra edildi. Skript əyləncəlidir? :) Və hamısı ona görə ki, proqramımızın işləməsi iplərin icra olunma ardıcıllığından asılıdır. Ardıcıllığın ən kiçik pozuntusunda mətbəximiz cəhənnəmə çevrilir və ağlını itirmiş robot ətrafdakı hər şeyi məhv edir. Bu, həm də bir neçə dəfə eşidəcəyiniz çoxillik proqramlaşdırmada ümumi problemdir. Mühazirənin sonunda mən sizə multithreading haqqında kitab tövsiyə etmək istərdim.
Java-da multithreading: mahiyyət, üstünlüklər və ümumi tələlər - 6
"Təcrübədə Java Paralelliyi" 2006-cı ildə yazılmışdır, lakin aktuallığını itirməmişdir. O, əsaslardan başlayaraq ən çox yayılmış səhvlərin və antipatternlərin siyahısı ilə bitən Java-da çoxillik proqramlaşdırmanı əhatə edir. Əgər siz nə vaxtsa çoxillik proqramlaşdırma gurusu olmaq qərarına gəlsəniz, bu kitab mütləq oxunmalıdır. Növbəti mühazirələrdə görüşənədək! :)
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION