Java'да көп агым менен чечүүчү көйгөйлөр
Негизинен, Java multithreading эки негизги маселени чечүү үчүн ойлоп табылган:-
Бир эле учурда бир нече аракеттерди аткарыңыз.
Жогорудагы мисалда ар кандай жиптер (б.а. үй-бүлө мүчөлөрү) параллелдүү бир нече иш-аракеттерди аткарышкан: идиштерди жуушту, дүкөнгө барышты, буюмдарды бүктөлдү.
Дагы бир "программист" мисал келтирүүгө болот. Сизде колдонуучу интерфейси бар программа бар деп элестетиңиз. Улантуу баскычы басылганда, программанын ичинде кээ бир эсептөөлөр болушу керек жана колдонуучу төмөнкү интерфейс экранын көрүшү керек. Бул аракеттер ырааттуу түрдө аткарылса, "Улантуу" баскычын басканда, программа жөн эле тоңуп калат. Колдонуучу ошол эле экранды "Улантуу" баскычы менен бардык ички эсептөөлөр аяктаганга чейин көрөт жана программа интерфейс тартыла турган бөлүккө жетет.
Мейли, бир-эки мүнөт күтөлү!
Биз ошондой эле программабызды кайра түзө алабыз, же программисттер айткандай, "параллелдештирүүгө" болот. Керектүү эсептөөлөр бир жипте, ал эми интерфейс рендеринг башкасында аткарылсын. Көпчүлүк компьютерлерде бул үчүн жетиштүү ресурстар бар. Бул учурда, программа "келесоо" болбойт жана колдонуучу ичинде эмне болуп жатканынан кабатырланбастан, интерфейс экрандарынын ортосунда тынч кыймылдайт. Бул кийлигишпейт :)
-
Эсептөөлөрдү тездетүү.
Бул жерде баары алда канча жөнөкөй. Эгерде биздин процессордо бир нече өзөк болсо, ал эми көпчүлүк процессорлор азыр көп ядролуу болсо, биздин милдеттерибиздин тизмеси бир нече ядро менен параллелдүү түрдө чечorши мүмкүн. Албетте, 1000 маселени чечүү керек болсо жана алардын ар бири бир секундда чечилсе, бир өзөк 1000 секундда, эки өзөк 500 секундда, үчөө 333 секунддан бир аз ашык убакытта жана башкалар менен чечет.
Thread
. Башкача айтканда, 10 жипти түзүү жана иштетүү үчүн бул класстын 10 an objectиси керек болот. Эң жөнөкөй мисалды жазалы:
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("I'm Thread! My name is " + getName());
}
}
Жиптерди түзүү жана ишке киргизүү үчүн класс түзүп, аны java.lang
. Thread
жана андагы ыкманы жокко чыгарыңыз run()
. Акыркысы абдан маанилүү. Бул ыкмада run()
биз логиканы биздин жип аткарышы керек деп белгилейбиз. Эми, эгерде биз инстанцияны түзүп MyFirstThread
, аны иштетсек, метод run()
консолго өзүнүн аты менен сапты басып чыгарат: ыкма getName()
жиптин "системалык" атын басып чыгарат, ал автоматтык түрдө дайындалат. Бирок, чынында, эмне үчүн "эгер"? Келгиле, түзөлү жана сынап көрөлү!
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Консолдун чыгышы: I'm Thread! Менин атым Thread-2 I'm Thread! Менин атым Thread-1 I'm Thread! Менин атым Thread-0 Мен Жипмин! Менин атым Thread-3 I'm Thread! Менин атым Thread-6 I'm Thread! Менин атым Thread-7 I'm Thread! Менин атым Thread-4 I'm Thread! Менин атым Thread-5 I'm Thread! Менин атым Thread-9 I'm Thread! Менин атым Thread-8MyFirstThread
Биз мураска алган 10 жипти (an objectтерди) түзөбүз Thread
жана аларды an objectтин ыкмасына чакыруу менен ишке киргизебиз start()
. Методду чакыргандан кийин start()
анын методу иштей баштайт run()
жана анда жазылган логика аткарылат. Көңүл буруңуз: жиптин аталыштары иреттүү эмес. Бул абдан кызык, эмне үчүн алар кезеги менен аткарылган эмес: Thread-0
, Thread-1
, Thread-2
жана башкалар? Бул стандарттуу, "ырааттуу" ой жүгүртүү иштебей турганынын так мисалы. Чындыгында, бул учурда биз 10 жипти түзүү жана ишке киргизүү үчүн гана буйруктарды чыгарабыз. Аларды кандай тартипте ишке киргизүү керектиги жип пландоочу тарабынан чечилет: операциялык системанын ичиндеги атайын механизм. Ал кандайча так түзүлөт жана кандай принципте чечим кабыл алат – бул өтө татаал тема, биз азыр ага тереңдеп кирбейбиз. Эсте турган негизги нерсе - программист жиптин аткарылышынын ырааттуулугун көзөмөлдөй алbyte. Кырдаалдын олуттуулугун түшүнүү үчүн, main()
жогорудагы мисалдагы ыкманы дагы бир нече жолу иштетип көрүңүз. Экинчи консол чыгаруу: Мен Threadмин! Менин атым Thread-0 Мен Жипмин! Менин атым Thread-4 I'm Thread! Менин атым Thread-3 I'm Thread! Менин атым Thread-2 I'm Thread! Менин атым Thread-1 I'm Thread! Менин атым Thread-5 I'm Thread! Менин атым Thread-6 I'm Thread! Менин атым Thread-8 I'm Thread! Менин атым Thread-9 I'm Thread! Менин атым Thread-7 Үчүнчү консолдун чыгышы: Мен Threadмин! Менин атым Thread-0 Мен Жипмин! Менин атым Thread-3 I'm Thread! Менин атым Thread-1 I'm Thread! Менин атым Thread-2 I'm Thread! Менин атым Thread-6 I'm Thread! Менин атым Thread-4 I'm Thread! Менин атым Thread-9 I'm Thread! Менин атым Thread-5 I'm Thread! Менин атым Thread-7 I'm Thread! Менин атым Thread-8
Көп агым жараткан көйгөйлөр
Китептер менен болгон мисалда сиз көп агым абдан маанилүү маселелерди чечерин жана аны колдонуу программаларыбыздын ишин тездеткенин көрдүңүз. Көп учурларда - көп жолу. Бирок multithreading татаал тема деп бекеринен айтылган эмес. Анткени, туура эмес колдонулса, аны чечүүнүн ордуна көйгөйлөрдү жаратат. Мен "көйгөйлөрдү жарат" деп айтканда, мен абстракттуу нерсени айткым келбейт. Multithreading алып келиши мүмкүн болгон эки өзгөчө көйгөй бар: туюк жана жарыш абалы. Туюктук - бул бир нече жиптер бири-бирин ээлеген ресурстарды күтүп турган жана алардын бири дагы аткарууну уланта албаган кырдаал. Биз бул тууралуу кийинки лекцияларда көбүрөөк сүйлөшөбүз, бирок азырынча бул мисал жетиштүү болот: 1-жип кандайдыр бир Объект-1 менен, ал эми жип-2 Объект-2 менен иштеп жатканын элестетиңиз. Программа мындайча жазылган:- Thread-1 Объект-1 менен иштөөнү токтотот жана Thread-2 Объект 2 менен иштөөнү токтотуп, Объект-1ге которулаар замат Объект-2ге өтөт.
- Thread-2 Объект-2 менен иштөөнү токтотот жана Thread-1 Объект 1 менен иштөөнү токтотуп, Объект-2ге которулаар замат Объект-1ге өтөт.
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();
}
}
}
Эми программа тамак даярдаган роботтун иштеши үчүн жооптуу экенин элестетиңиз! Жип-0 муздаткычтан жумурткаларды алат. 1-агым мешти күйгүзөт. Агым-2 сковородканы алып мешке коёт. 3-агым мешке от жагат. Stream 4 табага май куябыз. Stream 5 жумурткаларды сындырып, сковородкага куят. Stream 6 снаряддарды таштанды челекке ыргытат. Stream-7 даяр омленген жумурткаларды ысыктан чыгарат. Поток-8 тарелкага жумуртка салат. Stream-9 идиш жууйт. Биздин программанын жыйынтыгын карагыла: Thread-0 аткарылган Thread-2 жип аткарылган Thread-1 жип аткарылган Thread-4 жип аткарылган Thread-9 жип аткарылган Thread-5 жип аткарылган Thread-8 жип аткарылган Thread-7 жип аткарылган Thread-7 жип аткарылды -3 Thread-6 жип аткарылды. Сценарий кызыктуубу? :) Жана баары, анткени биздин программанын иштеши жиптер аткарылган тартипте көз каранды. Кичинекей эле ырааттуулук бузулганда ашканабыз тозокко айланат, ал эми жинди болгон робот айланасындагы нерселердин баарын жок кылат. Бул дагы көп агымдуу программалоодо кеңири таралган көйгөй, аны сиз бир нече жолу уга аласыз. Лекциянын аягында мен сизге көп агым боюнча китепти сунуштайм.
GO TO FULL VERSION