CodeGym /จาวาบล็อก /สุ่ม /การซิงโครไนซ์เธรด ตัวดำเนินการซิงโครไนซ์
John Squirrels
ระดับ
San Francisco

การซิงโครไนซ์เธรด ตัวดำเนินการซิงโครไนซ์

เผยแพร่ในกลุ่ม
สวัสดี! วันนี้เราจะพิจารณาคุณสมบัติของการเขียนโปรแกรมแบบมัลติเธรดต่อไป และพูดคุยเกี่ยวกับการซิงโครไนซ์เธรด การซิงโครไนซ์เธรด  ตัวดำเนินการซิงโครไนซ์ - 1

การซิงโครไนซ์ใน Java คืออะไร?

ภายนอกโดเมนการเขียนโปรแกรม หมายถึงการจัดการที่อนุญาตให้อุปกรณ์หรือโปรแกรมสองเครื่องทำงานร่วมกัน ตัวอย่างเช่น สมาร์ทโฟนและคอมพิวเตอร์สามารถซิงโครไนซ์กับบัญชี Google และบัญชีเว็บไซต์สามารถซิงโครไนซ์กับบัญชีโซเชียลเน็ตเวิร์กได้ ดังนั้นคุณจึงลงชื่อเข้าใช้บัญชีเหล่านี้ได้ การซิงโครไนซ์เธรดมีความหมายคล้ายกัน นั่นคือการจัดเรียงที่เธรดโต้ตอบกับ กันและกัน. ในบทเรียนก่อนหน้านี้ เธรดของเราอาศัยและทำงานแยกจากกัน คนหนึ่งทำการคำนวณ คนที่สองหลับ และคนที่สามแสดงบางอย่างบนคอนโซล แต่พวกเขาไม่ได้โต้ตอบ ในโปรแกรมจริง สถานการณ์เช่นนี้เกิดขึ้นได้ยาก หลายเธรดสามารถทำงานและแก้ไขชุดข้อมูลเดียวกันได้ สิ่งนี้สร้างปัญหา ลองนึกภาพหลายๆ เธรดที่เขียนข้อความไปยังที่เดียวกัน เช่น ไปยังไฟล์ข้อความหรือคอนโซล ในกรณีนี้ ไฟล์หรือคอนโซลจะกลายเป็นทรัพยากรที่ใช้ร่วมกัน เธรดไม่รู้จักการดำรงอยู่ของกันและกัน ดังนั้นพวกเขาจึงเขียนทุกอย่างที่ทำได้ในเวลาที่กำหนดโดยตัวกำหนดตารางเวลาเธรด ในบทเรียนเมื่อเร็วๆ นี้ เราเห็นตัวอย่างว่าสิ่งนี้นำไปสู่ที่ใด จำตอนนี้: การซิงโครไนซ์เธรด  ตัวดำเนินการซิงโครไนซ์ - 2เหตุผลอยู่ที่ความจริงที่ว่าเธรดกำลังทำงานกับทรัพยากรที่ใช้ร่วมกัน (คอนโซล) โดยไม่ประสานการกระทำซึ่งกันและกัน หากตัวกำหนดตารางเวลาของเธรดจัดสรรเวลาให้กับเธรด-1 ก็จะเขียนทุกอย่างลงในคอนโซลทันที สิ่งที่เธรดอื่นมีหรือยังไม่ได้จัดการในการเขียนไม่สำคัญ ผลลัพธ์อย่างที่คุณเห็นคือน่าหดหู่ใจ นั่นเป็นเหตุผลที่พวกเขาแนะนำแนวคิดพิเศษmutex (การยกเว้นซึ่งกันและกัน)ในการเขียนโปรแกรมแบบมัลติเธรด วัตถุประสงค์ของมิวเท็กซ์คือการจัดเตรียมกลไกเพื่อให้มีเพียงหนึ่งเธรดที่สามารถเข้าถึงออบเจกต์ได้ในเวลาหนึ่งๆ หากเธรด-1 ได้รับ mutex ของวัตถุ A เธรดอื่นจะไม่สามารถเข้าถึงและแก้ไขวัตถุได้ เธรดอื่นต้องรอจนกว่า mutex ของวัตถุ A จะถูกปล่อย นี่คือตัวอย่างจากชีวิต: ลองนึกภาพว่าคุณและคนแปลกหน้าอีก 10 คนกำลังเข้าร่วมในการออกกำลังกาย ผลัดกัน คุณต้องแสดงความคิดของคุณและหารือเกี่ยวกับบางสิ่งบางอย่าง แต่เนื่องจากคุณเพิ่งเจอกันเป็นครั้งแรก เพื่อไม่ให้เกิดการขัดจังหวะกันและโกรธเกรี้ยว คุณจึงใช้ 'ลูกบอลพูด': เฉพาะผู้ที่มีลูกบอลเท่านั้นที่สามารถพูดได้ ด้วยวิธีนี้คุณจะได้การสนทนาที่ดีและเกิดผล โดยพื้นฐานแล้ว ลูกบอลเป็นมิวเท็กซ์ ถ้า mutex ของอ็อบเจ็กต์อยู่ในมือของเธรดหนึ่ง เธรดอื่นๆ จะไม่สามารถทำงานกับอ็อบเจ็กต์ได้Objectคลาสซึ่งหมายความว่าทุกวัตถุใน Java มีหนึ่ง

วิธีการทำงานของตัวดำเนินการซิงโครไนซ์

มาทำความรู้จักกับคีย์เวิร์ดใหม่: ซิงโครไนซ์ มันถูกใช้เพื่อทำเครื่องหมายบล็อกของรหัส ถ้าบล็อกโค้ดถูกทำเครื่องหมายด้วยsynchronizedคีย์เวิร์ด บล็อกนั้นจะดำเนินการได้ครั้งละหนึ่งเธรดเท่านั้น การซิงโครไนซ์สามารถทำได้หลายวิธี ตัวอย่างเช่น โดยการประกาศเมธอดทั้งหมดที่จะซิงโครไนซ์:

public synchronized void doSomething() {

   // ...Method logic
}
หรือเขียนบล็อกรหัสที่ดำเนินการซิงโครไนซ์โดยใช้วัตถุบางอย่าง:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
ความหมายนั้นง่าย หากเธรดหนึ่งเข้าไปภายในบล็อคโค้ดที่มีsynchronizedคำสำคัญกำกับไว้ เธรดนั้นจะจับ mutex ของอ็อบเจ็กต์ทันที และเธรดอื่นๆ ทั้งหมดที่พยายามเข้าสู่บล็อคหรือเมธอดเดียวกันจะถูกบังคับให้รอจนกว่าเธรดก่อนหน้าจะทำงานเสร็จและปล่อยมอนิเตอร์ การซิงโครไนซ์เธรด  ตัวดำเนินการซิงโครไนซ์ - 3อนึ่ง! ในระหว่างหลักสูตร คุณได้เห็นตัวอย่างแล้วsynchronizedแต่ดูแตกต่างออกไป:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
หัวข้อนี้ใหม่สำหรับคุณ และแน่นอนว่าจะเกิดความสับสนกับไวยากรณ์ ดังนั้นให้จำทันทีเพื่อไม่ให้สับสนในภายหลังจากวิธีการเขียนแบบต่างๆ วิธีเขียนทั้งสองนี้มีความหมายเหมือนกัน:

public void swap() {

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


public synchronized void swap() {

   }
}
ในกรณีแรก คุณจะสร้างบล็อกโค้ดที่ซิงโครไนซ์ทันทีที่ป้อนเมธอด มันถูกซิงโครไนซ์โดยthisวัตถุ กล่าวคือ วัตถุปัจจุบัน และในตัวอย่างที่สอง คุณใช้synchronizedคีย์เวิร์ดกับเมธอดทั้งหมด ทำให้ไม่จำเป็นต้องระบุวัตถุที่ใช้สำหรับการซิงโครไนซ์อย่างชัดเจน เนื่องจากเมธอดทั้งหมดถูกทำเครื่องหมายด้วยคีย์เวิร์ด เมธอดจะถูกซิงโครไนซ์โดยอัตโนมัติสำหรับทุกอินสแตนซ์ของคลาส เราจะไม่ถกกันว่าทางไหนดีกว่ากัน สำหรับตอนนี้ เลือกวิธีใดก็ได้ที่คุณชอบที่สุด :) สิ่งสำคัญที่ต้องจำไว้: คุณสามารถประกาศวิธีการที่ซิงโครไนซ์ได้ก็ต่อเมื่อตรรกะทั้งหมดของมันถูกดำเนินการโดยเธรดหนึ่งครั้ง ตัวอย่างเช่น การซิงโครไนซ์เมธอดต่อไปนี้อาจเป็นข้อผิดพลาดdoSomething():

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
อย่างที่คุณเห็น ส่วนหนึ่งของวิธีการมีตรรกะที่ไม่ต้องการการซิงโครไนซ์ โค้ดนั้นสามารถเรียกใช้โดยหลายเธรดในเวลาเดียวกัน และตำแหน่งที่สำคัญทั้งหมดจะถูกแยกออกจากกันในsynchronizedบล็อก แยกต่างหาก และอีกสิ่งหนึ่ง ลองพิจารณาตัวอย่างของเราอย่างใกล้ชิดจากบทเรียนที่มีการสลับชื่อกัน:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
หมายเหตุ:การซิงโครไนซ์ดำเนินการโดยใช้this. นั่นคือการใช้MyClassวัตถุสมมติว่าเรามี 2 เธรด (Thread-1และThread-2) และMyClass myClassวัตถุในกรณีนี้ หากThread-1เรียกใช้myClass.swap()เมธอด mutex ของออบเจ็กต์จะไม่ว่าง และเมื่อพยายามเรียกใช้myClass.swap()เมธอดThread-2จะหยุดทำงานขณะรอการเผยแพร่ mutex หากเราจะมี 2 เธรดและ 2MyClassออบเจ็กต์ (myClass1และmyClass2) เธรดของเราสามารถเรียกใช้เมธอดที่ซิงโครไนซ์พร้อมกันบนออบเจ็กต์ต่างๆ ได้อย่างง่ายดาย เธรดแรกดำเนินการนี้:

myClass1.swap();
ที่สองดำเนินการนี้:

myClass2.swap();
ในกรณีนี้synchronizedคำหลักภายในswap()เมธอดจะไม่ส่งผลต่อการทำงานของโปรแกรม เนื่องจากการซิงโครไนซ์จะดำเนินการโดยใช้วัตถุเฉพาะ และในกรณีหลัง เรามีวัตถุ 2 ชิ้น กระทู้จึงไม่สร้างปัญหาให้กัน ท้ายที่สุดแล้ว วัตถุ 2 ชิ้น มี 2 mutexes ที่แตกต่างกัน และการได้มาซึ่งสิ่งหนึ่งนั้นไม่ขึ้นอยู่กับการได้มาซึ่งอีกสิ่งหนึ่ง

คุณสมบัติพิเศษของการซิงโครไนซ์ในวิธีคงที่

แต่ถ้าคุณต้องการซิงโครไนซ์เมธอดแบบคง ที่ ล่ะ

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

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

}
ยังไม่ชัดเจนว่า mutex จะมีบทบาทอย่างไรที่นี่ ท้ายที่สุด เราได้พิจารณาแล้วว่าแต่ละออบเจกต์มีมิวเท็กซ์ แต่ปัญหาคือเราไม่ต้องการให้วัตถุเรียกMyClass.swap()เมธอด: เมธอดเป็นแบบสแตติก! แล้วอะไรต่อไป? :/ ที่จริงไม่มีปัญหาที่นี่ ผู้สร้างของ Java ดูแลทุกอย่าง :) หากเมธอดที่มีตรรกะพร้อมกันที่สำคัญเป็นแบบสแตติก การซิงโครไนซ์จะดำเนินการที่ระดับคลาส เพื่อความชัดเจนยิ่งขึ้น เราสามารถเขียนโค้ดด้านบนใหม่ได้ดังนี้:

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static void swap() {

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

}
โดยหลักการแล้ว คุณอาจคิดเรื่องนี้ได้เอง: เนื่องจากไม่มีออบเจกต์ กลไกการซิงโครไนซ์จะต้องถูกรวมเข้ากับคลาสด้วยวิธีการใดวิธีหนึ่ง และนั่นคือวิธีการ: เราสามารถใช้คลาสเพื่อซิงโครไนซ์
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION