JavaRush /Java Blog /Random-TL /Pag-synchronize ng thread. Naka-synchronize na operator s...

Pag-synchronize ng thread. Naka-synchronize na operator sa Java

Nai-publish sa grupo
Kamusta! Ngayon ay patuloy nating isasaalang-alang ang mga tampok ng multi-threaded programming at pag-uusapan ang tungkol sa pag-synchronize ng thread.
Pag-synchronize ng thread.  Naka-synchronize ang operator - 1
Ano ang “synchronization”? Sa labas ng programming realm, ito ay tumutukoy sa ilang uri ng setup na nagbibigay-daan sa dalawang device o program na magtulungan. Halimbawa, ang isang smartphone at computer ay maaaring i-synchronize sa isang Google account, at ang isang personal na account sa isang website ay maaaring i-synchronize sa mga account sa mga social network upang mag-log in gamit ang mga ito. Ang pag-synchronize ng thread ay may katulad na kahulugan: ito ay nagse-set up kung paano nakikipag-ugnayan ang mga thread sa isa't isa. Sa mga nakaraang lektura, ang aming mga thread ay nanirahan at nagtrabaho nang hiwalay sa isa't isa. Ang isa ay nagbibilang ng isang bagay, ang pangalawa ay natutulog, ang pangatlo ay nagpapakita ng isang bagay sa console, ngunit hindi sila nakikipag-ugnayan sa isa't isa. Sa totoong mga programa, bihira ang mga ganitong sitwasyon. Maraming mga thread ang maaaring aktibong gumana, halimbawa, na may parehong hanay ng data at baguhin ang isang bagay sa loob nito. Lumilikha ito ng mga problema. Isipin na maraming thread ang nagsusulat ng text sa parehong lokasyon, gaya ng text file o console. Ang file o console na ito sa kasong ito ay nagiging isang nakabahaging mapagkukunan. Hindi alam ng mga thread ang tungkol sa pag-iral ng isa't isa, kaya isusulat lang nila ang lahat ng maaari nilang pamahalaan sa oras na ilalaan sa kanila ng thread scheduler. Sa isang kamakailang lecture ng kurso, mayroon kaming isang halimbawa ng kung ano ang hahantong dito, tandaan natin ito: Pag-synchronize ng thread.  Naka-synchronize na operator - 2Ang dahilan ay nakasalalay sa katotohanan na ang mga thread ay nagtrabaho sa isang nakabahaging mapagkukunan, ang console, nang hindi nag-uugnay sa kanilang mga aksyon sa isa't isa. Kung ang thread scheduler ay naglaan ng oras sa Thread-1, agad nitong isusulat ang lahat sa console. Kung ano ang nagawang isulat ng ibang mga thread o hindi pa naisulat ay hindi mahalaga. Ang resulta, tulad ng nakikita mo, ay nakapipinsala. Samakatuwid, sa multi-threaded programming, isang espesyal na konsepto na mutex ang ipinakilala (mula sa Ingles na "mutex", "mutual exclusion" - "mutual exclusion") . Ang layunin ng isang mutex ay magbigay ng isang mekanismo upang ang isang thread lamang ang may access sa isang bagay sa isang tiyak na oras. Kung nakuha ng Thread-1 ang mutex ng object A, ang ibang mga thread ay hindi magkakaroon ng access dito upang baguhin ang anumang bagay dito. Hanggang sa mailabas ang mutex ng object A, mapipilitang maghintay ang natitirang mga thread. Halimbawa sa totoong buhay: isipin na ikaw at ang 10 iba pang estranghero ay nakikilahok sa isang pagsasanay. Kailangan mong magsalitan sa pagpapahayag ng mga ideya at pagtalakay ng isang bagay. Ngunit, dahil unang beses kayong nagkita, upang hindi patuloy na makagambala sa isa't isa at hindi magkagulo, ginagamit mo ang panuntunang "talking ball": isang tao lamang ang maaaring magsalita - ang may hawak ng bola. kanyang mga kamay. Sa ganitong paraan lumalabas na sapat at mabunga ang talakayan. Kaya, ang isang mutex, sa esensya, ay tulad ng isang bola. Kung ang mutex ng isang bagay ay nasa kamay ng isang thread, hindi maa-access ng ibang mga thread ang bagay. Hindi mo kailangang gumawa ng anumang bagay upang lumikha ng isang mutex: ito ay naka-built na sa class Object, na nangangahulugang ang bawat bagay sa Java ay mayroon nito.

Paano gumagana ang naka-synchronize na operator sa Java

Maging pamilyar tayo sa isang bagong keyword - naka-synchronize . Ito ay nagmamarka ng isang partikular na piraso ng aming code. Kung ang isang bloke ng code ay minarkahan ng naka-synchronize na keyword, nangangahulugan ito na ang block ay maaari lamang isagawa ng isang thread sa isang pagkakataon. Maaaring ipatupad ang pag-synchronize sa iba't ibang paraan. Halimbawa, lumikha ng isang buong naka-synchronize na paraan:
public synchronized void doSomething() {

   //...method logic
}
O magsulat ng isang bloke ng code kung saan isinasagawa ang pag-synchronize sa ilang bagay:
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
       }
   }
}
Simple lang ang kahulugan. Kung ang isang thread ay pumasok sa isang bloke ng code na minarkahan ng salitang naka-synchronize, agad nitong makukuha ang mutex ng object, at lahat ng iba pang mga thread na sumusubok na pumasok sa parehong bloke o pamamaraan ay mapipilitang maghintay hanggang sa makumpleto ng nakaraang thread ang trabaho nito at ilabas ang subaybayan. Pag-synchronize ng thread.  Naka-synchronize na operator - 3Siya nga pala! Sa mga lektura ng kurso nakakita ka na ng mga halimbawa ng naka-synchronize, ngunit iba ang hitsura nila:
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
Ang paksa ay bago para sa iyo, at siyempre magkakaroon ng kalituhan sa syntax sa simula. Samakatuwid, tandaan kaagad upang hindi malito mamaya sa mga paraan ng pagsulat. Iisa ang ibig sabihin ng dalawang paraan ng pagsulat na ito:
public void swap() {

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


public synchronized void swap() {

   }
}
Sa unang kaso, lumikha ka ng isang naka-synchronize na bloke ng code kaagad sa pagpasok ng pamamaraan. Ito ay naka-synchronize ng object this, iyon ay, ng kasalukuyang object. At sa pangalawang halimbawa ay inilagay mo ang salitang naka-synchronize sa buong pamamaraan. Hindi na kailangang tahasang ipahiwatig ang anumang bagay kung saan isinasagawa ang pag-synchronize. Kapag ang isang buong pamamaraan ay minarkahan ng isang salita, ang pamamaraang ito ay awtomatikong masi-synchronize para sa lahat ng mga bagay ng klase. Huwag na nating pasukin ang talakayan kung aling pamamaraan ang mas mahusay. Sa ngayon, piliin kung ano ang gusto mo :) Ang pangunahing bagay ay tandaan: maaari mong ideklara ang isang pamamaraan na naka-synchronize lamang kapag ang lahat ng lohika sa loob nito ay naisakatuparan ng isang thread nang sabay-sabay. Halimbawa, sa kasong ito, doSomething()magiging isang error ang pag-synchronize ng pamamaraan:
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
       }
   }
}
Tulad ng nakikita mo, ang isang piraso ng pamamaraan ay naglalaman ng lohika kung saan hindi kinakailangan ang pag-synchronize. Ang code sa loob nito ay maaaring isagawa ng maraming mga thread nang sabay-sabay, at ang lahat ng mga kritikal na lugar ay inilalaan sa isang hiwalay na naka-synchronize na bloke. At isang sandali. Tingnan natin sa ilalim ng mikroskopyo ang aming halimbawa mula sa panayam na may pagpapalitan ng mga pangalan:
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
Pakitandaan: ang pag-synchronize ay isinasagawa gamit ang this. Iyon ay, para sa isang partikular na bagay MyClass. Isipin na mayroon kaming 2 mga thread ( Thread-1at Thread-2) at isang bagay lamang MyClass myClass. Sa kasong ito, kung Thread-1ang pamamaraan ay tinatawag na myClass.swap(), ang mutex ng bagay ay magiging abala, at Thread-2kapag sinubukan mong tawagan ito, myClass.swap()ito ay mag-hang naghihintay para sa mutex na maging libre. Kung mayroon kaming 2 mga thread at 2 mga bagay MyClass- myClass1at myClass2- sa iba't ibang mga bagay, ang aming mga thread ay madaling sabay na magsagawa ng mga naka-synchronize na pamamaraan. Ang unang thread ay:
myClass1.swap();
Ginagawa ng pangalawa:
myClass2.swap();
Sa kasong ito, ang naka-synchronize na keyword sa loob ng pamamaraan swap()ay hindi makakaapekto sa pagpapatakbo ng programa, dahil ang pag-synchronize ay isinasagawa sa isang partikular na bagay. At sa huling kaso, mayroon kaming 2 bagay. Samakatuwid, ang mga thread ay hindi gumagawa ng mga problema para sa bawat isa. Pagkatapos ng lahat, ang dalawang bagay ay may 2 magkaibang mutex, at ang kanilang pagkuha ay hindi nakasalalay sa isa't isa.

Mga tampok ng pag-synchronize sa mga static na pamamaraan

Ngunit paano kung kailangan mong i-synchronize ang isang static na pamamaraan?
class MyClass {
   private static String name1 = "Olya";
   private static String name2 = "Lena";

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

}
Hindi malinaw kung ano ang magsisilbing mutex sa kasong ito. Pagkatapos ng lahat, napagpasyahan na namin na ang bawat bagay ay may mutex. Ngunit ang problema ay upang tumawag ng isang static na pamamaraan MyClass.swap()hindi namin kailangan ng mga bagay: ang pamamaraan ay static! Kaya, ano ang susunod? :/ Actually, walang problema dito. Ang mga tagalikha ng Java ay nag-ingat sa lahat :) Kung ang pamamaraan na naglalaman ng kritikal na "multithreaded" na lohika ay static, ang pag-synchronize ay isasagawa ayon sa klase. Para sa higit na kalinawan, ang code sa itaas ay maaaring muling isulat bilang:
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;
       }
   }

}
Sa prinsipyo, maaari mong naisip ito sa iyong sarili: dahil walang mga bagay, kung gayon ang mekanismo ng pag-synchronize ay dapat na kahit papaano ay "naka-hardwired" sa mga klase mismo. Ganito iyon: maaari ka ring mag-synchronize sa mga klase.
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION