JavaRush /Java блогу /Random-KY /Жипти синхрондоштуруу. Java тилинде синхрондоштуруу опера...

Жипти синхрондоштуруу. Java тилинде синхрондоштуруу оператору

Группада жарыяланган
Салам! Бүгүн биз көп жиптүү программалоонун өзгөчөлүктөрүн карап чыгууну улантабыз жана жипти синхрондоштуруу жөнүндө сүйлөшөбүз.
Жипти синхрондоштуруу.  Оператор синхрондуу - 1
"синхрондоштуруу" деген эмне? Программалоо чөйрөсүнөн тышкары, бул эки түзмөккө же программага чогуу иштөөгө мүмкүндүк берген кандайдыр бир орнотууну билдирет. Мисалы, смартфон менен компьютерди Google аккаунту менен, ал эми веб-сайттагы жеке аккаунтту социалдык тармактардагы аккаунттар менен синхрондоштурууга болот, аларды колдонуу менен кирүү үчүн. Жипти синхрондоштуруу окшош мааниге ээ: ал жиптердин бири-бири менен өз ара аракеттенүүсүн орнотуу. Мурунку лекцияларда биздин жиптер бири-биринен өзүнчө жашап жана иштеп келген. Бири бир нерсени санап жаткан, экинчиси уктап жаткан, үчүнчүсү консолдо бир нерсени көрсөтүп жаткан, бирок алар бири-бири менен иштешкен эмес. Реалдуу программаларда мындай жагдайлар сейрек кездешет. Бир нече жиптер, мисалы, бир эле маалыматтар топтому менен активдүү иштеп, андагы бир нерсени өзгөртө алат. Бул көйгөйлөрдү жаратат. Бир нече жиптер текст файлы же консол сыяктуу бир жерге текст жазып жатканын элестетиңиз. Бул файл же консол бул учурда жалпы ресурс болуп калат. Жиптер бири-биринин бар экенин бorшпейт, ошондуктан алар жип пландоочусу аларга бөлгөн убакыттын ичинде колунан келгендин баарын жазышат. Курстун жакында эле өткөн лекциясында бул эмнеге алып келерин мисалга тарттык, муну эстеп көрөлү: Жипти синхрондоштуруу.  Синхрондуу оператор - 2Мунун себеби жиптер бири-бири менен аракеттерди координациялабастан, жалпы ресурс, консол менен иштегендигинде. Эгерде жип пландоочусу Thread-1ге убакыт бөлсө, ал дароо консолго баарын жазат. Башка темалар буга чейин жаза алганы же жаза албаганы маанилүү эмес. Натыйжа, сиз көрүп тургандай, каргашалуу. Ошондуктан, көп жиптүү программалоодо атайын мутекс түшүнүгү киргизилген (англисчеден “mutex”, “mutual exclusion” – “mutual exclusion”) . Мутекстин максаты белгилүү бир убакта an objectке бир гана жип кире алгыдай механизмди камсыз кылуу. Эгерде Thread-1 А an objectинин мутексине ээ болсо, анда башка жиптер андагы эч нерсени өзгөртүү үчүн ага кире алbyte. А an objectинин мутекси чыгарылганга чейин, калган жиптер күтүүгө аргасыз болушат. Чыныгы жашоодон мисал: сиз жана башка 10 бейтааныш адам тренингге катышып жатканыңызды элестетиңиз. Кезектешип ойлорду айтып, бир нерсени талкуулашыңыз керек. Бирок, сиз бири-бириңизди биринчи жолу көрүп жатканыңыздан улам, бири-бириңизди үзгүлтүккө учуратпоо үчүн жана "сүйлөшүүчү топ" эрежесин колдоносуз: бир гана адам сүйлөй алат - кимде топ болсо, ошол сүйлөй алат. анын колдору. Ошентип талкуу адекваттуу жана жемиштүү болуп чыгат. Демек, мутекс, маңызы боюнча, ушундай шар. Эгерде an objectтин мутекси бир жиптин колунда болсо, башка жиптер an objectке кире алbyte. Мутексти түзүү үчүн эч нерсе кылуунун кереги жок: ал класска мурунтан эле орнотулган Object, демек Javaдагы ар бир an objectте бар.

Шайкештештирилген оператор Java тorнде кантип иштейт

Келгиле, жаңы ачкыч сөз менен таанышалы - синхрондуу . Бул биздин codeдун белгилүү бир бөлүгүн белгилейт. Эгерде code блогу синхрондоштурулган ачкыч сөз менен белгиленсе, бул блок бир эле учурда бир жип менен аткарыла тургандыгын билдирет. Синхрондоштуруу ар кандай жолдор менен ишке ашырылышы мүмкүн. Мисалы, бүтүндөй синхрондоштурулган ыкманы түзүңүз:
public synchronized void doSomething() {

   //...method logic
}
Же кандайдыр бир an objectте синхрондоштуруу жүргүзүлүүчү code блогун жазыңыз:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       synchronized (obj) {

           //logic that is only available to one thread at a time
       }
   }
}
Мааниси жөнөкөй. Эгерде бир жип синхрондоштурулган сөз менен белгиленген code блогуна кирсе, ал ошол замат an objectтин мутексине ээ болот жана ошол эле блокко же ыкмага кирүүгө аракет кылган бардык башка жиптер мурунку жип өз ишин аяктагыча күтүүгө аргасыз болушат. монитор. Жипти синхрондоштуруу.  Синхрондуу оператор - 3Айтмакчы! Курстук лекцияларда сиз синхрондоштурулган мисалдарды көрдүңүз, бирок алар башкача көрүндү:
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
Тема сиз үчүн жаңы жана, албетте, алгач синтаксис менен чаташуулар болот. Ошондуктан, кийинчерээк жазуу ыкмаларын чаташтырбоо үчүн дароо эстеп алыңыз. Бул эки жазуу ыкмалары бир эле нерсени билдирет:
public void swap() {

   synchronized (this)
   {
       //...method logic
   }
}


public synchronized void swap() {

   }
}
Биринчи учурда, сиз ыкманы киргизгенден кийин дароо codeдун синхрондуу блогун түзөсүз. thisАл an object менен , башкача айтканда, учурдагы an object менен шайкештештирилет . Ал эми экинчи мисалда сиз синхрондоштурулган сөздү бүт ыкмага койдуңуз. Синхрондоштуруу жүргүзүлүп жаткан an objectти ачык көрсөтүүнүн кереги жок. Бүтүндөй ыкма сөз менен белгиленгенден кийин, бул ыкма класстын бардык an objectилери үчүн автоматтык түрдө синхрондолот. Келгиле, кайсы ыкма жакшыраак экенин талкуулоого киришпейли. Азырынча, сизге эң жаккан нерсени тандаңыз :) Эң негизгиси эсиңизде болсун: сиз методду анын ичиндеги бардык логика бир эле учурда бир жип менен аткарылганда гана синхрондоштурулган деп жарыялай аласыз. Мисалы, бул учурда doSomething()ыкманы синхрондоштуруу ката болот:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       synchronized (obj) {

           //logic that is only available to one thread at a time
       }
   }
}
Көрүнүп тургандай, методдун бир бөлүгү синхрондоштурууну талап кылбаган логиканы камтыйт. Андагы code бир эле учурда бир нече жиптер тарабынан аткарылышы мүмкүн жана бардык критикалык жерлер өзүнчө синхрондоштурулган блокко бөлүнгөн. Жана бир көз ирмем. Келгиле, микроскоптун астында аттарды алмаштыруу менен лекциядагы мисалыбызды карап көрөлү:
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
Эскертүү: синхрондоштуруу this. Башкача айтканда, белгилүү бир an object үчүн MyClass. Элестеткиле, бизде 2 жип ( Thread-1жана Thread-2) жана бир гана an object бар MyClass myClass. Бул учурда, эгерде Thread-1метод деп аталса myClass.swap(), an objectтин мутекси бош эмес болот жана Thread-2сиз аны чакырганга аракет кылганыңызда, myClass.swap()ал мутекстин бош болушун күтүп асылып калат. Эгерде бизде 2 жип жана 2 an object бар болсо MyClass- myClass1жана myClass2- ар кандай an objectтерде, биздин жиптер бир эле учурда синхрондуу ыкмаларды оңой эле аткара алат. Биринчи жип төмөнкүдөй кылат:
myClass1.swap();
Экинчиси:
myClass2.swap();
Бул учурда, методдун ичиндеги синхрондоштурулган ачкыч сөз swap()программанын иштешине таасирин тийгизбейт, анткени синхрондоштуруу белгилүү бир an objectте жүргүзүлөт. Ал эми акыркы учурда бизде 2 an object бар.Ошондуктан жиптер бири-бирине көйгөй жаратпайт. Анткени, эки an objectиде 2 түрдүү мутекс бар жана алардын кармалышы бири-биринен көз каранды эмес.

Статикалык методдордо синхрондоштуруунун өзгөчөлүктөрү

Бирок статикалык ыкманы синхрондоштуруу керек болсочу?
class MyClass {
   private static String name1 = "Olya";
   private static String name2 = "Lena";

   public static synchronized void swap() {
       String s = name1;
       name1 = name2;
       name2 = s;
   }

}
Бул учурда мутекс катары эмне кызмат кылаары белгисиз. Анткени, биз буга чейин эле ар бир an objectтин мутекси бар деп чечкенбиз. Бирок маселе статикалык методду чакыруу үчүн MyClass.swap()бизге an objectтердин кереги жок: метод статикалык! Анда эмне болот? :/ Чынында, бул менен эч кандай көйгөй жок. Java түзүүчүлөрү бардыгына кам көрүштү :) Эгерде критикалык “көп агымдуу” логиканы камтыган метод статикалык болсо, синхрондоштуруу класс тарабынан ишке ашырылат. Көбүрөөк түшүнүктүү болуу үчүн, жогорудагы codeду төмөнкүдөй кайра жазса болот:
class MyClass {
   private static String name1 = "Olya";
   private static String name2 = "Lena";

   public static void swap() {

       synchronized (MyClass.class) {
           String s = name1;
           name1 = name2;
           name2 = s;
       }
   }

}
Негизи, сиз бул жөнүндө өз алдынча ойлонсоңуз болмок: an objectтер жок болгондуктан, синхрондоштуруу механизми кандайдыр бир жол менен класстардын өздөрүнө "катуу" болушу керек. Мына ушундай: сиз класстар боюнча синхрондоштурууга да болот.
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION