JavaRush /Java блогы /Random-KK /Көп ағынды: жіп класының әдістері не істейді

Көп ағынды: жіп класының әдістері не істейді

Топта жарияланған
Сәлеметсіз бе! Бүгін біз көп ағынды туралы сөйлесуді жалғастырамыз. Thread класын және оның бірнеше әдістерінің қалай жұмыс істейтінін қарастырайық. Бұрын біз сынып әдістерін зерттегенде, біз оны көбінесе былай жазатынбыз: «әдіс атауы» -> «ол не істейді».
Multithreading: Thread класының әдістері не істейді - 1
Бұл Thread әдістерімен жұмыс істемейді :) Олардың логикасы күрделірек және бірнеше мысалдарсыз түсіну мүмкін емес.

Thread.start() әдісі

Қайталаудан бастайық. Естеріңізде болса керек, сыныпты сыныптан мұраға алу Threadжәне ондағы әдісті қайта анықтау арқылы ағынды жасауға болады run(). Бірақ, әрине, ол өздігінен басталмайды. Ол үшін an objectіміздегі әдісті шақырамыз start(). Multithreading: Thread класының әдістері не істейді - 2Алдыңғы лекциядағы мысалды еске түсірейік:
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();
       }
   }
}
Назар аударыңыз: ағынды бастау үшін!start()емес,run()Бұл оңай қате, әсіресе көп ағынды үйрену кезінде. run()Біздің мысалда 10 рет орнынанысан әдісін шақырсаңызstart(), нәтиже келесідей болады:
public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
Тақырып-0 ағыны орындалды Тақырып-1 ағын орындалды Тақырып-2 ағын орындалды Тақырып-3 ағын орындалды Тақырып-4 ағын орындалды Тақырып-5 ағын орындалды Тақырып-6 ағын орындалды. Шығару ретін қараңыз: бәрі қатаң тәртіппен жүреді. Біртүрлі, иә? Біз бұған үйренген жоқпыз, өйткені ағындардың іске қосылу және орындалу реті операциялық жүйеміздің ішіндегі супербарлау - ағынды жоспарлаушы арқылы анықталатынын біз бұрыннан білеміз. Мүмкін менің жолым болған шығар? Әрине, бұл сәттілік емес. Мұны бағдарламаны бірнеше рет іске қосу арқылы тексеруге болады. Мәселе мынада, әдісті тікелей шақыруrun()көп ағынмен ешқандай байланысы жоқ. Бұл жағдайда бағдарлама негізгі ағында орындалады - әдіс орындалатынmain(). Ол жай ғана консольге 10 жолды дәйекті түрде шығарады және бәрі бірдей. 10 ағын басталмайды. Сондықтан болашақты есте сақтаңыз және өзіңізді үнемі тексеріп отырыңыз. Егер сіз мұны істегіңіз келсеrun(), оны шақырыңызstart(). Әрі қарай жүрейік.

Thread.sleep() әдісі

Ағымдағы ағынның орындалуын біраз уақытқа кідірту үшін пайдаланыңыз sleep(). Multithreading: Thread класының әдістері не істейді - 3Әдіс sleep()параметр ретінде миллисекундтар санын, яғни жіпті ұйқы режиміне қою қажет уақытты алады.
public class Main {

   public static void main(String[] args) throws InterruptedException {

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - Сколько я проспал? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " секунды");

   }
}
Консоль шығысы: - Мен қанша уақыт ұйықтадым? - 3 секунд Назар аударыңыз: әдіс sleep()статикалық: ол ағымдағы ағынды ұйқы режиміне қояды. Яғни, қазіргі уақытта жұмыс істеп жатқан. Тағы бір маңызды нюанс: ұйқы күйіндегі ағын үзілуі мүмкін. Бұл жағдайда бағдарламада ерекше жағдай орын алады InterruptedException. Төмендегі мысалды қарастырамыз. Айтпақшы, жіп «оянғаннан» кейін не болады? Ол тоқтаған жерінен дереу орындалуын жалғастыра ма? Жоқ. Жіп оянғаннан кейін - дәлел ретінде өткен уақыт біткенде - ол орындалатынThread.sleep() күйге өтеді . Дегенмен, бұл ағынды жоспарлаушы оны іске қосады дегенді білдірмейді. Ол басқа «ұйқысыз» жіпке артықшылық беруі әбден мүмкін, ал біздің «жаңадан оянған» жіп сәл кейінірек жұмысын жалғастырады. Есіңізде болсын: «Ояну дәл осы секундта жұмысты жалғастыруды білдірмейді!»

Thread.join() әдісі

Многопоточность: что делают методы класса Thread - 4Әдіс join()ағымдағы ағынның орындалуын басқа ағын аяқталғанша тоқтатады. Егер бізде 2 ағын болса, t1және t2, және біз жазамыз -
t1.join()
t2t1 жұмысын аяқтамайынша жұмысқа кіріспейді. Әдіс join()ағындардың орындалу ретін қамтамасыз ету үшін пайдаланылуы мүмкін. join()Мысал арқылы жұмысты қарастырайық :
public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Начало работы потока " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Поток " + getName() +  " завершил работу.");
   }
}


public class Main {

   public static void main(String[] args) throws InterruptedException {

       ThreadExample t1 = new ThreadExample();
       ThreadExample t2 = new ThreadExample();

       t1.start();


 /*Второй поток t2 начнет выполнение только после того, How будет завершен
       (or бросит исключение) первый поток - t1*/
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       //Главный поток продолжит работу только после того, How t1 и t2 завершат работу
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("Все потоки закончor работу, программа завершена");

   }
}
Біз қарапайым класс құрдық ThreadExample. Оның міндеті - экранда жұмыстың басталуы туралы хабарламаны көрсету, содан кейін 5 секунд ұйықтап, соңында жұмыстың аяқталғаны туралы хабарлау. Күрделі ештеңе жоқ. Негізгі логика сыныпта қамтылған Main. Түсініктемелерді қараңыз: әдісті қолдана отырып, join()біз ағындардың орындалу ретін сәтті басқарамыз. Тақырыптың басы есіңізде болса, ағынды жоспарлаушы мұны жасады. Ол оларды өз қалауы бойынша іске қосты: әр жолы басқаша. t1Мұнда әдісті қолдана отырып, біз алдымен ағынның , содан кейін ағынның t2және тек олардан кейін бағдарламаның орындалуының негізгі ағынының іске қосылуын және орындалуын қамтамасыз еттік . Ілгері жүру. Нақты бағдарламаларда сіз кейбір ағынның орындалуын үзу қажет болатын жағдайларға жиі тап боласыз. Мысалы, біздің ағын жұмыс істеп тұр, бірақ ол белгілі бір оқиғаның немесе шарттың орындалуын күтуде. Бұл орын алса, ол тоқтайды. сияқты әдіс болса, қисынды болар еді stop(). Дегенмен, бәрі соншалықты қарапайым емес. Бір кездері Thread.stop()Java-да әдіс шынымен болған және ағынның жұмысын тоқтатуға мүмкіндік берді. Бірақ кейінірек ол Java кітапханасынан жойылды. Сіз оны Oracle құжаттамасынан іздеп, оның ескірген деп белгіленгенін көре аласыз . Неліктен? Өйткені ол ешқандай қосымша жұмыссыз ағынды жай ғана тоқтатты. Мысалы, ағын деректермен жұмыс істей алады және ондағы бір нәрсені өзгерте алады. stop()Содан кейін ол жұмыстың ортасында кенеттен нокаутқа түсті - және солай болды. Ешқандай дұрыс өшіру, ресурстарды босату, тіпті қателерді өңдеу болмады - мұның ешқайсысы болмады. Әдіс stop(), асыра айтсақ, жолындағының бәрін жойды. Оның жұмысын біреудің компьютерді өшіру үшін розеткадан қалай тартып алғанымен салыстыруға болады. Иә, сіз қалаған нәтижеге қол жеткізе аласыз. Бірақ бәрі бір-екі аптадан кейін компьютер бұл үшін «рахмет» айтпайтынын түсінеді. Осы себепті Java-да ағындарды үзу логикасы өзгертілді және қазір арнайы әдіс қолданылады - interrupt().

Thread.interrupt() әдісі

Егер сіз ағындағы әдісті шақырсаңыз не болады interrupt()? 2 нұсқа бар:
  1. Егер нысан сол сәтте күту күйінде болса, мысалы, joinнемесе sleep, күту үзіліп, бағдарлама лақтырады InterruptedException.
  2. Егер ағын сол сәтте жұмыс күйінде болса, нысанның логикалық жалауы орнатылады interrupted.
Бірақ біз бұл тудың құндылығын an objectіні тексеріп, жұмысты өзіміз дұрыс аяқтауымыз керек! Осы мақсатта сыныпта Threadарнайы әдіс бар - boolean isInterrupted(). Негізгі курс лекциясынан сағат үлгісіне оралайық. Ыңғайлы болу үшін ол сәл жеңілдетілген:
public class Clock extends Thread {

   public static void main(String[] args) throws InterruptedException {
       Clock clock = new Clock();
       clock.start();

       Thread.sleep(10000);
       clock.interrupt();
   }

   public void run() {
       Thread current = Thread.currentThread();

       while (!current.isInterrupted())
       {
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               System.out.println("Работа потока была прервана");
               break;
           }
           System.out.println("Tik");
       }
   }
}
Біздің жағдайда сағат әр секунд сайын басталады және басталады. 10 секундта біз сағат ағынын үземіз. Өздеріңіз білетіндей, егер біз үзуге тырысып жатқан ағын күту күйлерінің бірінде болса, бұл нәтижеге әкеледі InterruptedException. Ерекшеліктің бұл түрі тексерілген ерекшелік болып табылады, сондықтан оны оңай ұстауға және бағдарламаны тоқтату логикасын орындауға болады. Біз осылай істедік. Міне, нәтиже: Tik Tik Tik Tik Tik Tik Tik Tik Tik Tik Tik Tik Жіп жұмысы үзілді.Осымен біздің сыныптың негізгі әдістеріне кіріспе аяқталады Thread. Біліміңізді бекіту үшін сіз көп ағындылық туралы мына бейне дәрісті көре аласыз:
бұл тамаша қосымша материал ретінде қызмет етеді! Соңында, әдістерді шолғаннан кейін, бұл курста ары қарай неден өтетінімізді нақты айтады :) Сәттілік!
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION