JavaRush /Java blogi /Random-UZ /Java-da multithreading: mohiyati, afzalliklari va umumiy ...

Java-da multithreading: mohiyati, afzalliklari va umumiy tuzoqlari

Guruhda nashr etilgan
Salom! Avvalo, tabriklaymiz: siz Java-da Multithreading mavzusiga yetib keldingiz! Bu jiddiy yutuq, oldinda uzoq yo'l bor. Lekin tayyor bo'ling: bu kursdagi eng qiyin mavzulardan biri. Va gap shundaki, bu erda murakkab sinflar yoki ko'plab usullar qo'llanilmaydi: aksincha, hatto yigirma ham yo'q. Ko'proq fikringizni biroz o'zgartirishingiz kerak. Ilgari dasturlaringiz ketma-ket bajarilgan. Ba'zi kod satrlari boshqalarga ergashdi, ba'zi usullar boshqalarga ergashdi va umuman hamma narsa aniq edi. Birinchidan, biror narsani hisoblang, so'ngra natijani konsolda ko'rsating, so'ngra dasturni to'xtating. Ko'p ish zarralarini tushunish uchun parallellik nuqtai nazaridan o'ylash yaxshidir. Keling, juda oddiy narsadan boshlaylik :) Java-da multithreading: mohiyati, afzalliklari va umumiy tuzoqlari - 1Tasavvur qiling, sizning oilangiz bir uydan ikkinchisiga ko'chib o'tmoqda. Ko'chirishning muhim qismi bu kitoblaringizni yig'ishdir. Sizda juda ko'p kitoblar to'plangan va ularni qutilarga solib qo'yishingiz kerak. Endi faqat siz ozodsiz. Onam ovqat tayyorlayapti, akasi kiyim yig'moqda, opa esa do'konga ketdi. Hech bo'lmaganda yolg'iz o'zingiz boshqarishingiz mumkin va ertami-kechmi, hatto o'zingiz ham vazifani bajarasiz, lekin bu juda ko'p vaqtni oladi. Biroq, 20 daqiqadan so'ng singlingiz do'kondan qaytib keladi va uning boshqa qiladigan ishlari yo'q. Shunday qilib, u sizga qo'shilishi mumkin. Vazifa bir xil bo'lib qoldi: kitoblarni qutilarga soling. U faqat ikki barobar tezroq ishlaydi. Nega? Chunki ish parallel ravishda amalga oshiriladi. Ikki xil "ip" (siz va singlingiz) bir vaqtning o'zida bir xil vazifani bajarmoqdasiz va agar hech narsa o'zgarmasa, vaqt farqi siz hamma narsani yolg'iz bajaradigan vaziyatga nisbatan juda katta bo'ladi. Agar birodaringiz o'z vazifasini tezda bajarsa, u sizga yordam berishi mumkin va ishlar tezroq ketadi.

Java'da multithreading hal qiladigan muammolar

Aslida, Java multithreading ikkita asosiy muammoni hal qilish uchun ixtiro qilingan:
  1. Bir vaqtning o'zida bir nechta amallarni bajaring.

    Yuqoridagi misolda turli xil iplar (ya'ni, oila a'zolari) parallel ravishda bir nechta harakatlarni amalga oshirdilar: idishlarni yuvdilar, do'konga bordilar, narsalarni katladilar.

    Ko'proq "dasturchi" misolini keltirish mumkin. Tasavvur qiling-a, sizda foydalanuvchi interfeysi bo'lgan dastur mavjud. Davom etish tugmasi bosilganda, dastur ichida ba'zi hisob-kitoblar amalga oshirilishi kerak va foydalanuvchi quyidagi interfeys ekranini ko'rishi kerak. Agar ushbu harakatlar ketma-ket bajarilsa, "Davom etish" tugmasini bosgandan so'ng, dastur shunchaki muzlaydi. Foydalanuvchi "Davom etish" tugmasi bilan bir xil ekranni barcha ichki hisob-kitoblar tugagunga qadar va dastur interfeys chizilishi boshlanadigan qismga yetguncha ko'radi.

    Xo'sh, bir necha daqiqa kutamiz!

    Java-da multithreading: mohiyati, afzalliklari va umumiy tuzoqlari - 3

    Biz dasturimizni qayta ishlab chiqishimiz yoki dasturchilar aytganidek, “parallellashtirish”imiz ham mumkin. Kerakli hisob-kitoblar bitta ipda, interfeysni ko'rsatish boshqasida amalga oshirilsin. Aksariyat kompyuterlarda buning uchun yetarli resurslar mavjud. Bunday holda, dastur "ahmoq" bo'lmaydi va foydalanuvchi ichkarida nima sodir bo'layotganidan xavotirlanmasdan, interfeys ekranlari o'rtasida xotirjamlik bilan harakat qiladi. Bu aralashmaydi :)

  2. Hisob-kitoblarni tezlashtiring.

    Bu erda hamma narsa ancha sodda. Agar bizning protsessorimiz bir nechta yadroga ega bo'lsa va ko'pchilik protsessorlar endi ko'p yadroli bo'lsa, bizning vazifalarimiz ro'yxati bir nechta yadrolar tomonidan parallel ravishda hal qilinishi mumkin. Shubhasiz, agar biz 1000 ta muammoni hal qilishimiz kerak bo'lsa va ularning har biri bir soniyada hal etilsa, bitta yadro 1000 soniyada, ikkita yadro 500 soniyada, uchtasi 333 soniyadan ko'proq vaqt ichida va hokazo.

Ammo, siz allaqachon ma'ruzada o'qiganingizdek, zamonaviy tizimlar juda aqlli va hatto bitta hisoblash yadrosida vazifalar navbatma-navbat bajarilganda parallelizm yoki psevdoparallelizmni amalga oshirishga qodir. Keling, umumiy narsalardan aniq narsalarga o'tamiz va Java kutubxonasida multithreading bilan bog'liq asosiy sinf - java.lang.Thread bilan tanishamiz. To'g'ri aytganda, Java'dagi mavzular sinf misollari bilan ifodalanadi Thread. Ya'ni, 10 ta ip yaratish va ishga tushirish uchun sizga ushbu sinfning 10 ta ob'ekti kerak bo'ladi. Eng oddiy misolni yozamiz:
public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("I'm Thread! My name is " + getName());
   }
}
Tarmoqlarni yaratish va ishga tushirish uchun biz sinf yaratishimiz va uni java.lang. Threadva undagi usulni bekor qiling run(). Oxirgisi juda muhim. Aynan usulda run()biz ipimiz bajarishi kerak bo'lgan mantiqni belgilaymiz. Endi, agar biz misol yaratsak MyFirstThreadva uni ishga tushirsak, usul run()konsolga o'z nomi bilan chiziqni chop etadi: usul getName()avtomatik ravishda tayinlangan ipning "tizim" nomini chop etadi. Garchi, aslida, nima uchun "agar"? Keling, yaratamiz va sinab ko'ramiz!
public class Main {

   public static void main(String[] args) {

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

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Konsol chiqishi: Men Threadman! Mening ismim Thread-2 Men mavzu! Mening ismim Thread-1 Men mavzu! Mening ismim Thread-0 Men mavzu! Mening ismim Thread-3 Men mavzu! Mening ismim Thread-6 Men mavzu! Mening ismim Thread-7 Men mavzu! Mening ismim Thread-4 Men mavzu! Mening ismim Thread-5 Men mavzu! Mening ismim Thread-9 Men mavzu! Mening ismim Thread-8MyFirstThread Biz meros qilib oladigan 10 ta mavzuni (ob'ektni) yaratamiz Threadva ularni ob'ekt usulini chaqirish orqali ishga tushiramiz start(). Metodni chaqirgandan so'ng , start()uning usuli ishlay boshlaydi run()va unda yozilgan mantiq bajariladi. Iltimos, diqqat qiling: mavzu nomlari tartibda emas. Bu juda g'alati, nega ular o'z navbatida qatl qilinmadi: Thread-0, Thread-1, Thread-2va hokazo? Bu standart, "ketma-ket" fikrlash ishlamasligiga aniq misol. Gap shundaki, bu holda biz faqat 10 ta ip yaratish va ishga tushirish uchun buyruq beramiz. Ularni qanday tartibda ishga tushirish kerakligi mavzuni rejalashtiruvchi tomonidan hal qilinadi: operatsion tizim ichidagi maxsus mexanizm. U qanday qilib aniq tuzilgan va qanday printsip asosida qaror qabul qiladi - bu juda murakkab mavzu va biz hozir unga sho'ng'imaymiz. Esda tutish kerak bo'lgan asosiy narsa shundaki, dasturchi ipni bajarish ketma-ketligini nazorat qila olmaydi. Vaziyatning jiddiyligini tushunish uchun main()yuqoridagi misoldagi usulni yana bir necha marta ishlatishga harakat qiling. Ikkinchi konsol chiqishi: Men Threadman! Mening ismim Thread-0 Men mavzu! Mening ismim Thread-4 Men mavzu! Mening ismim Thread-3 Men mavzu! Mening ismim Thread-2 Men mavzu! Mening ismim Thread-1 Men mavzu! Mening ismim Thread-5 Men mavzu! Mening ismim Thread-6 Men mavzu! Mening ismim Thread-8 Men mavzu! Mening ismim Thread-9 Men mavzu! Mening ismim Thread-7 Uchinchi konsol chiqishi: Men Threadman! Mening ismim Thread-0 Men mavzu! Mening ismim Thread-3 Men mavzu! Mening ismim Thread-1 Men mavzu! Mening ismim Thread-2 Men mavzu! Mening ismim Thread-6 Men mavzu! Mening ismim Thread-4 Men mavzu! Mening ismim Thread-9 Men mavzu! Mening ismim Thread-5 Men mavzu! Mening ismim Thread-7 Men mavzu! Mening ismim Thread-8

Ko'p ish zarralarini yaratish muammolari

Kitoblar misolida siz ko'p ish zarralari juda muhim muammolarni hal qilishini va undan foydalanish dasturlarimiz ishini tezlashtirishini ko'rdingiz. Ko'p hollarda - ko'p marta. Ammo ko'p ish zarralarini o'tkazish murakkab mavzu deb hisoblanishi bejiz emas. Axir, noto'g'ri ishlatilsa, ularni hal qilish o'rniga muammolarni keltirib chiqaradi. Men "muammolar yaratish" deganimda, men mavhum narsani nazarda tutmayman. Ko'p ish zarralari sabab bo'lishi mumkin bo'lgan ikkita o'ziga xos muammo mavjud: tugash va poyga holati. Tugallanish - bu bir nechta oqimlar bir-biri bilan band bo'lgan resurslarni kutayotgan va ularning hech biri ishlashni davom ettira olmaydigan holat. Kelgusi ma'ruzalarda bu haqda ko'proq gaplashamiz, ammo hozircha bu misol etarli bo'ladi: Java-da multithreading: mohiyati, afzalliklari va umumiy tuzoqlari - 4 Tasavvur qiling-a, thread-1 qandaydir Ob'ekt-1 bilan ishlayapti va thread-2 Ob'ekt-2 bilan ishlayapti. Dastur quyidagicha yozilgan:
  1. Thread-1 ob'ekt-1 bilan ishlashni to'xtatadi va Thread-2 2-ob'ekt bilan ishlashni to'xtatib, Ob'ekt-1ga o'tishi bilanoq Ob'ekt-2 ga o'tadi.
  2. Thread-1 1-ob'ekt bilan ishlashni to'xtatib, Ob'ekt-2 ga o'tish bilanoq, Thread-2 Ob'ekt-2 bilan ishlashni to'xtatadi va Ob'ekt-1 ga o'tadi.
Ko'p ish zarralarini chuqur bilmasangiz ham, undan hech narsa chiqmasligini osongina tushunishingiz mumkin. Iplar hech qachon o'rnini o'zgartirmaydi va bir-birini abadiy kutadi. Xato aniq ko'rinadi, lekin aslida unday emas. Siz uni dasturga osongina kiritishingiz mumkin. Biz keyingi ma'ruzalarda blokirovkaga olib keladigan kod misollarini ko'rib chiqamiz. Aytgancha, Quorada boshi berk ko'cha nima ekanligini tushuntiruvchi ajoyib haqiqiy misol bor . “Hindistonning ayrim shtatlarida, agar siz fermer sifatida roʻyxatdan oʻtmasangiz, ular sizga qishloq xoʻjaligi erlarini sotmaydi. Ammo qishloq xo‘jaligiga oid yeringiz bo‘lmasa, fermer sifatida ro‘yxatga olinmaysiz”. Ajoyib, nima deyishim mumkin! :) Endi poyga sharti haqida - poyga holati. Poyga sharti - bu tizim yoki dasturning ishlashi kod qismlarining bajarilishi tartibiga bog'liq bo'lgan ko'p tarmoqli tizim yoki dasturdagi dizayn nuqsonidir. Ishlayotgan iplar bilan misolni eslang: Java-da multithreading: mohiyati, afzalliklari va umumiy tuzoqlari - 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();
       }
   }
}
Endi tasavvur qiling-a, dastur oziq-ovqat tayyorlaydigan robotning ishlashi uchun javobgardir! Thread-0 tuxumni muzlatgichdan oladi. Stream 1 pechkani yoqadi. Stream-2 qovurilgan idishni olib, pechka ustiga qo'yadi. 3-oqim pechkada olov yoqadi. Stream 4 skovorodkaga yog' quying. Stream 5 tuxumni sindirib, ularni qovurilgan idishga quyadi. Stream 6 chig'anoqlarni axlat qutisiga tashlaydi. Stream-7 tayyor omletni issiqdan olib tashlaydi. Potok-8 omletni plastinka ustiga qo'yadi. Stream-9 idishlarni yuvadi. Dasturimiz natijalarini ko'ring: Thread-0 bajarildi Mavzu-2 bajarildi Mavzu-1 mavzu bajarildi Mavzu-4 mavzu bajarildi Mavzu-9 mavzu bajarildi Mavzu-5 mavzu bajarildi. ip bajarildi -3 Thread-6 ip bajarildi. Skript qiziqarlimi? :) Va barchasi, chunki bizning dasturimizning ishlashi iplarning bajarilish tartibiga bog'liq. Ketma-ketlikning eng kichik buzilishi bilan bizning oshxonamiz do'zaxga aylanadi va aqldan ozgan robot uning atrofidagi hamma narsani yo'q qiladi. Bu, shuningdek, ko'p bosqichli dasturlashda keng tarqalgan muammo bo'lib, siz bu haqda bir necha marta eshitasiz. Ma'ruza yakunida men sizga multithreading bo'yicha kitobni tavsiya qilmoqchiman.
Java-da multithreading: mohiyati, afzalliklari va umumiy tuzoqlari - 6
"Java Concurrency in Practice" 2006 yilda yozilgan, ammo o'z ahamiyatini yo'qotmagan. U Java-da ko'p bosqichli dasturlashni o'z ichiga oladi, asosiylardan boshlab va eng keng tarqalgan xatolar va antipatternlar ro'yxati bilan yakunlanadi. Agar siz ko'p bosqichli dasturlash gurusi bo'lishga qaror qilsangiz, bu kitobni o'qish kerak. Keyingi ma'ruzalarda ko'rishguncha! :)
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION