JavaRush /Java блогу /Random-KY /Java'да көп агым: маңызы, артыкчылыктары жана жалпы тузак...

Java'да көп агым: маңызы, артыкчылыктары жана жалпы тузактар

Группада жарыяланган
Салам! Биринчиден, куттуктайбыз: Java тorндеги Multithreading темасына жеттиңиз! Бул олуттуу жетишкендик, алдыда узак жол бар. Бирок даяр болуңуз: бул курстагы эң татаал темалардын бири. Кеп бул жерде татаал класстар же көптөгөн методдор колдонулуп жатканында эмес: тескерисинче, ал тургай эки ондогон да жок. Андан көрө ой жүгүртүүңдү бир аз өзгөртүү керек. Мурда сиздин программаларыңыз ырааттуу түрдө аткарылчу. Коддун кээ бир саптары башкаларды, кээ бир ыкмалар башкаларды ээрчип, жалпысынан баары түшүнүктүү болду. Биринчиден, бир нерсени эсептеп, натыйжаны консолдо көрсөтүңүз, андан кийин программаны токтотуңуз. Көп агымды түшүнүү үчүн, параллелдүүлүк боюнча ойлонуу жакшы. Эң жөнөкөй нерседен баштайлы :) Javaдагы көп агым: маңызы, жакшы жактары жана жалпы тузактар ​​- 1Сиздин үй-бүлөңүз бир үйдөн экинчи үйгө көчүп жатканын элестетиңиз. Көчүүнүн маанилүү бөлүгү - бул китептериңизди жыйноо. Сиз көп китептерди топтодуңуз, аларды кутуларга салуу керек. Эми сен гана эркинсиң. Апам тамак даярдап жатат, агам кийим чогултуп жатат, эжем дүкөнгө кетти. Жалгыз сиз, жок дегенде, башкара аласыз, жана, эртеби-кечпи, ал тургай, өзүңүз бүтүрөсүз, бирок бул көп убакытты талап кылат. Бирок, 20 мүнөттөн кийин эжең дүкөндөн келет, анын башка кыла турган иши жок. Ошентип, ал сага кошула алат. Тапшырма ошол эле бойдон калды: китептерди кутуларга салуу. Ал болгону эки эсе ылдам иштейт. Неге? Анткени иш параллелдүү жүрүп жатат. Эки башка "жип" (сиз жана эжеңиз) бир эле учурда бир эле тапшырманы аткарып жатасыз жана эч нерсе өзгөрбөсө, сиз баарын жалгыз жасай турган кырдаалга салыштырмалуу убакыт айырмасы абдан чоң болот. Эгер бир тууганың тапшырмасын тез арада бүтүрсө, ал сага жардам бере алат жана баары тезирээк болот.

Java'да көп агым менен чечүүчү көйгөйлөр

Негизинен, Java multithreading эки негизги маселени чечүү үчүн ойлоп табылган:
  1. Бир эле учурда бир нече аракеттерди аткарыңыз.

    Жогорудагы мисалда ар кандай жиптер (б.а. үй-бүлө мүчөлөрү) параллелдүү бир нече иш-аракеттерди аткарышкан: идиштерди жуушту, дүкөнгө барышты, буюмдарды бүктөлдү.

    Дагы бир "программист" мисал келтирүүгө болот. Сизде колдонуучу интерфейси бар программа бар деп элестетиңиз. Улантуу баскычы басылганда, программанын ичинде кээ бир эсептөөлөр болушу керек жана колдонуучу төмөнкү интерфейс экранын көрүшү керек. Бул аракеттер ырааттуу түрдө аткарылса, "Улантуу" баскычын басканда, программа жөн эле тоңуп калат. Колдонуучу ошол эле экранды "Улантуу" баскычы менен бардык ички эсептөөлөр аяктаганга чейин көрөт жана программа интерфейс тартыла турган бөлүккө жетет.

    Мейли, бир-эки мүнөт күтөлү!

    Java'да көп агым: маңызы, артыкчылыктары жана жалпы тузактар ​​- 3

    Биз ошондой эле программабызды кайра түзө алабыз, же программисттер айткандай, "параллелдештирүүгө" болот. Керектүү эсептөөлөр бир жипте, ал эми интерфейс рендеринг башкасында аткарылсын. Көпчүлүк компьютерлерде бул үчүн жетиштүү ресурстар бар. Бул учурда, программа "келесоо" болбойт жана колдонуучу ичинде эмне болуп жатканынан кабатырланбастан, интерфейс экрандарынын ортосунда тынч кыймылдайт. Бул кийлигишпейт :)

  2. Эсептөөлөрдү тездетүү.

    Бул жерде баары алда канча жөнөкөй. Эгерде биздин процессордо бир нече өзөк болсо, ал эми көпчүлүк процессорлор азыр көп ядролуу болсо, биздин милдеттерибиздин тизмеси бир нече ядро ​​менен параллелдүү түрдө чечorши мүмкүн. Албетте, 1000 маселени чечүү керек болсо жана алардын ар бири бир секундда чечилсе, бир өзөк 1000 секундда, эки өзөк 500 секундда, үчөө 333 секунддан бир аз ашык убакытта жана башкалар менен чечет.

Бирок, сиз буга чейин лекцияда окуганыңыздай, заманбап системалар абдан акылдуу, жада калса бир эсептөө өзөгүндө алар параллелизмди же псевдопараллелизмди ишке ашыра алышат, милдеттер кезектешип аткарылганда. Келгиле, жалпы нерселерден конкреттүү нерселерге өтөлү жана Java китепканасында көп агымга байланыштуу негизги класс - java.lang.Thread менен таанышалы. Тактап айтканда, Javaдагы жиптер класстын инстанциялары менен көрсөтүлөт 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 алып келиши мүмкүн болгон эки өзгөчө көйгөй бар: туюк жана жарыш абалы. Туюктук - бул бир нече жиптер бири-бирин ээлеген ресурстарды күтүп турган жана алардын бири дагы аткарууну уланта албаган кырдаал. Биз бул тууралуу кийинки лекцияларда көбүрөөк сүйлөшөбүз, бирок азырынча бул мисал жетиштүү болот: Java'да көп агым: маңызы, артыкчылыктары жана жалпы тузактар ​​- 4 1-жип кандайдыр бир Объект-1 менен, ал эми жип-2 Объект-2 менен иштеп жатканын элестетиңиз. Программа мындайча жазылган:
  1. Thread-1 Объект-1 менен иштөөнү токтотот жана Thread-2 Объект 2 менен иштөөнү токтотуп, Объект-1ге которулаар замат Объект-2ге өтөт.
  2. Thread-2 Объект-2 менен иштөөнү токтотот жана Thread-1 Объект 1 менен иштөөнү токтотуп, Объект-2ге которулаар замат Объект-1ге өтөт.
Көп агымды терең билбесе да, андан эч нерсе чыкпай турганын оңой эле түшүнө аласыз. Жиптер эч качан ордун алмаштырbyte жана бири-бирин түбөлүк күтүшөт. Ката ачык көрүнөт, бирок иш жүзүндө андай эмес. Сиз аны программага оңой эле киргизе аласыз. Биз кийинки лекцияларда туюк абалга алып келген codeдун мисалдарын карап чыгабыз. Айтмакчы, Quoraда туюктун эмне экенин түшүндүргөн эң сонун реалдуу мисал бар . «Индиядагы кээ бир штаттарда фермер катары катталмайынча, алар сизге айыл чарба жерлерин сатпайт. Ал эми айыл чарба багытындагы жерлериң болбосо, дыйкан катары каттоодон өтпөйсүң”. Керемет, мен эмне дей алам! :) Эми жарыштын абалы жөнүндө - жарыштын абалы. Жарыш шарты – бул системанын же тиркеменин иштеши codeдун бөлүктөрү аткарылган тартиптен көз каранды болгон көп жиптүү тутумдагы же тиркемедеги долбоорлоо кемчorги. Иштеп жаткан жиптер менен мисалды эстеңиз: Javaдагы көп агым: маңызы, жакшы жактары жана жалпы тузактар ​​- 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();
       }
   }
}
Эми программа тамак даярдаган роботтун иштеши үчүн жооптуу экенин элестетиңиз! Жип-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 жип аткарылды. Сценарий кызыктуубу? :) Жана баары, анткени биздин программанын иштеши жиптер аткарылган тартипте көз каранды. Кичинекей эле ырааттуулук бузулганда ашканабыз тозокко айланат, ал эми жинди болгон робот айланасындагы нерселердин баарын жок кылат. Бул дагы көп агымдуу программалоодо кеңири таралган көйгөй, аны сиз бир нече жолу уга аласыз. Лекциянын аягында мен сизге көп агым боюнча китепти сунуштайм.
Javaдагы көп агым: маңызы, жакшы жактары жана жалпы тузактар ​​- 6
"Java Concurrency in Practice" 2006-жылы жазылган, бирок актуалдуулугун жогото элек. Ал Java тorндеги көп агымдуу программалоону камтыйт, негизгилерден баштап эң кеңири таралган каталардын жана антипаттерндердин тизмеси менен аяктайт. Эгер сиз көп агымдуу программалоо гурусу болууну чечсеңиз, бул китепти сөзсүз окушуңуз керек. Кийинки лекцияларда көрүшкөнчө! :)
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION