'ทำข้อมูลให้ตรงกัน' หมายความว่าอย่างไร


993

ฉันมีคำถามบางอย่างเกี่ยวกับการใช้งานและความสำคัญของsynchronizedคำหลัก

  • คำสำคัญของsynchronizedคำสำคัญคืออะไร
  • วิธีการควรเป็นเมื่อไหร่synchronized?
  • มันหมายถึงอะไรโดยทางโปรแกรมและเหตุผล?


1
การอภิปรายที่เป็นประโยชน์ระหว่าง hashmap และ hashtable และการซิงโครไนซ์: stackoverflow.com/questions/40471/java-hashmap-vs-hashtable
limc

2
การทำสำเนาข้อมูลที่เป็นไปได้ของการทำงานข้อมูลให้ตรงกันใน Java
Marian Paździoch

1
ฉันผ่านลิงค์เอกสารทั้งหมดจากความคิดเห็นแรกและไม่เข้าใจจนกว่าฉันจะไปถึงย่อหน้าสุดท้าย แทนที่จะวางลิงก์และอ้างถึงสิ่งใด ๆ การวางลิงก์และการเพิ่มเครื่องหมายคำพูดนั้นมีประโยชน์มากกว่า
Rakib

คำตอบ:


878

synchronizedคำหลักคือทั้งหมดที่เกี่ยวกับหัวข้อที่แตกต่างกันอ่านและการเขียนตัวแปรเดียวกันวัตถุและทรัพยากร นี่ไม่ใช่หัวข้อเล็กน้อยใน Java แต่นี่เป็นคำพูดจาก Sun:

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

โดยสรุปแล้วมีขนาดเล็กมาก:เมื่อคุณมีสองเธรดที่อ่านและเขียนไปยัง 'ทรัพยากร' เดียวกันพูดชื่อตัวแปรfooคุณต้องแน่ใจว่าเธรดเหล่านี้เข้าถึงตัวแปรในวิธีอะตอมมิก หากไม่มีsynchronizedคำหลักเธรด 1 ของคุณอาจไม่เห็นเธรดการเปลี่ยนแปลง 2 ที่ทำขึ้นfooหรือแย่ลงมันอาจเปลี่ยนไปเพียงครึ่งเดียว นี่จะไม่ใช่สิ่งที่คุณคาดหวังอย่างมีเหตุผล

อีกครั้งนี่เป็นหัวข้อที่ไม่สำคัญใน Java หากต้องการเรียนรู้เพิ่มเติมสำรวจหัวข้อที่นี่ใน SO และ Interwebs เกี่ยวกับ:

สำรวจหัวข้อเหล่านี้ต่อไปจนกว่าชื่อ"Brian Goetz"จะเชื่อมโยงอย่างถาวรกับคำว่า"การเกิดพร้อมกัน"ในสมองของคุณ


71
ดังนั้นโดยทั่วไปคำหลักที่ซิงโครไนซ์นี้ทำให้เมธอดของคุณปลอดภัยหรือไม่?
Rigo Vides

82
คำหลักที่ซิงโครไนซ์เป็นหนึ่งในเครื่องมือที่ทำให้เธรดโค้ดของคุณปลอดภัย เพียงใช้การซิงโครไนซ์กับเมธอดหรือตัวแปรในตัวมันเองอาจจะใช่หรือไม่ก็ได้ การมีความเข้าใจพื้นฐานเกี่ยวกับ Java Memory Model เป็นสิ่งสำคัญมากในการแก้ไขภาวะพร้อมกัน
Stu Thompson

28
นอกจากว่าคุณจะเป็น Brian Goetz (หรือ Jon Skeet) ก็แทบจะเป็นไปไม่ได้ที่จะให้การทำงานพร้อมกันของ Java ถูกต้องด้วยภาษาดั้งเดิมเท่านั้น สำหรับ starters ใช้ประโยชน์จากแพ็คเกจ java.util.concurrent และสร้างขึ้นมาใหม่
Thilo

12
ชัดเจนยิ่งขึ้น: วิธีการซิงโครไนซ์ไม่สามารถเรียกใช้ในเวลาเดียวกันจากหลายเธรด
peterh - Reinstate Monica

2
@peterh ทำข้อมูลให้ตรงกันมากกว่านั้นด้วยเหตุนี้คำอธิบายที่ละเอียดมากขึ้น
Stu Thompson

293

ฉันคิดว่าเรามีคำอธิบายทางทฤษฎีเพียงพอแล้วดังนั้นให้พิจารณารหัสนี้

public class SOP {
    public static void print(String s) {
        System.out.println(s+"\n");
    }
}

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;
    public TestThread(String name,TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }
    @Override
    public void run() {
        theDemo.test(name);
    }
}

public class TheDemo {
    public synchronized void test(String name) {
        for(int i=0;i<10;i++) {
            SOP.print(name + " :: "+i);
            try{
                Thread.sleep(500);
            } catch (Exception e) {
                SOP.print(e.getMessage());
            }
        }
    }
    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1",theDemo);
        new TestThread("THREAD 2",theDemo);
        new TestThread("THREAD 3",theDemo);
    }
}

หมายเหตุ: synchronizedบล็อกการเรียกเธรดถัดไปของการทดสอบ method () ตราบใดที่การดำเนินการของเธรดก่อนหน้ายังไม่เสร็จสิ้น เธรดสามารถเข้าถึงวิธีนี้ทีละครั้ง ไม่มีsynchronizedเธรดทั้งหมดสามารถเข้าถึงวิธีนี้พร้อมกัน

เมื่อเธรดเรียกใช้ 'การทดสอบ' ของวิธีการซิงโครไนซ์ของวัตถุ (ที่นี่วัตถุเป็นตัวอย่างของคลาส 'TheDemo') มันได้รับการล็อคของวัตถุนั้นเธรดใหม่ใด ๆ ที่ไม่สามารถเรียกวิธีการทำข้อมูลให้ตรงกันใด ๆ ของวัตถุเดียวกัน ซึ่งได้รับล็อคไม่ได้ปลดล็อค

สิ่งที่คล้ายกันเกิดขึ้นเมื่อมีการเรียกใช้วิธีการซิงโครไนส์แบบคงที่ใด ๆ ของคลาส เธรดจะได้รับการล็อคที่เกี่ยวข้องกับคลาส (ในกรณีนี้วิธีการซิงโครไนซ์แบบไม่คงที่ใด ๆ ของอินสแตนซ์ของคลาสนั้นสามารถเรียกได้โดยเธรดใด ๆ เนื่องจากการล็อกระดับวัตถุนั้นยังคงมีอยู่) เธรดอื่น ๆ จะไม่สามารถเรียกใช้วิธีการซิงโครไนซ์แบบคงที่ใด ๆ ของคลาสได้ตราบใดที่การล็อกระดับคลาสไม่ถูกปล่อยโดยเธรดซึ่งปัจจุบันถือล็อคอยู่

เอาต์พุตพร้อมซิงโครไนซ์

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

เอาต์พุตโดยไม่ซิงโครไนซ์

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9

7
ตัวอย่างที่ดีมันเป็นเรื่องดีที่จะรู้ทฤษฎี แต่รหัสนั้นเจาะจงและสมบูรณ์กว่าเสมอ
Santi Iglesias

2
@SantiIglesias "เสร็จสมบูรณ์" หรือไม่ Nope ตัวอย่างนี้แสดงให้เห็นถึงพฤติกรรมการล็อคของsynchronizedแต่ความสอดคล้องของหน่วยความจำจะถูกละเว้น
Stu Thompson

2
ความสอดคล้องของหน่วยความจำ @Stu Thompson เป็นผลมาจากการล็อก
Dheeraj Sachan

@DheerajSachan โดยตรรกะนั้นจากนั้นใช้ ReentrantLock จะส่งผลให้มันสอดคล้องหน่วยความจำ มันไม่ได้
Stu Thompson

3
@boltup_im_coding: เมธอด start () ทำให้เธรดอยู่ในสถานะ "RUNNABLE" ซึ่งหมายความว่าพร้อมสำหรับการดำเนินการหรือดำเนินการแล้ว มันอาจเกิดขึ้นที่หัวข้ออื่น (ปกติ แต่ไม่จำเป็นต้องมีลำดับความสำคัญสูงกว่า) ในสถานะ Runnable กระโดดข้ามคิวและเริ่มดำเนินการ ในตัวอย่างข้างต้นมีเธรด 3 เกิดขึ้นเพื่อรับ CPU ก่อนที่เธรด 2
Sahil J

116

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

เมื่อใช้synchronizedงานที่ไม่ใช่โครงสร้างHashMapคุณต้องสร้างคุณสมบัติความปลอดภัยของเธรดในรหัสของคุณเพื่อป้องกันข้อผิดพลาดที่สอดคล้องกัน


81

synchronizedหมายความว่าในสภาพแวดล้อมแบบมัลติเธรดวัตถุที่มี synchronizedวิธีการ / บล็อก (s) จะไม่ปล่อยให้สองเธรดเข้าถึงsynchronizedวิธี / บล็อก (s) ของรหัสในเวลาเดียวกัน ซึ่งหมายความว่าหนึ่งเธรดไม่สามารถอ่านได้ในขณะที่เธรดอื่นอัปเดต

เธรดที่สองจะรอจนกว่าเธรดแรกจะเสร็จสิ้นการดำเนินการ ค่าใช้จ่ายคือความเร็ว แต่ข้อดีคือรับประกันความสอดคล้องของข้อมูล

หากแอปพลิเคชันของคุณเป็นเธรดเดี่ยวแม้ว่าsynchronizedบล็อกจะไม่ให้ประโยชน์


54

synchronizedคำหลักที่ทำให้เกิดด้ายเพื่อให้ได้ล็อคเมื่อเข้าสู่วิธีการเพื่อให้มีเพียงหนึ่งหัวข้อสามารถดำเนินการวิธีการในเวลาเดียวกัน (เช่นวัตถุที่กำหนดเว้นแต่จะเป็นวิธีการคงที่)

สิ่งนี้มักถูกเรียกว่าการทำให้คลาสของเธรดปลอดภัย แต่ฉันจะบอกว่านี่เป็นคำสละสลวย แม้ว่าจะเป็นความจริงที่การซิงโครไนซ์จะป้องกันสถานะภายในของ Vector จากการได้รับความเสียหาย แต่ก็ไม่ได้ช่วยผู้ใช้ Vector มากนัก

พิจารณาสิ่งนี้:

 if (vector.isEmpty()){
     vector.add(data);
 }

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

ดังนั้นคุณต้องซิงโครไนซ์ในรหัสแอปพลิเคชันของคุณด้วย

เนื่องจากการซิงโครไนซ์ระดับวิธีการ a) แพงเมื่อคุณไม่ต้องการและ b) ไม่เพียงพอเมื่อคุณต้องการการซิงโครไนซ์ตอนนี้มีการแทนที่ที่ไม่ซิงโครไนซ์ (ArrayList ในกรณีของ Vector)

เมื่อไม่นานมานี้แพ็คเกจการทำงานพร้อมกันได้รับการเผยแพร่พร้อมกับยูทิลิตี้ที่ชาญฉลาดจำนวนมากที่ดูแลปัญหาการเธรดหลายเธรด


26

ภาพรวม

คีย์เวิร์ดที่ซิงโครไนซ์ใน Java เกี่ยวข้องกับความปลอดภัยของเธรดนั่นคือเมื่อหลายเธรดอ่านหรือเขียนตัวแปรเดียวกัน
สิ่งนี้สามารถเกิดขึ้นได้โดยตรง (โดยการเข้าถึงตัวแปรเดียวกัน) หรือทางอ้อม (โดยใช้คลาสที่ใช้คลาสอื่นที่เข้าถึงตัวแปรเดียวกัน)

คีย์เวิร์ดที่ซิงโครไนซ์ใช้เพื่อกำหนดกลุ่มของรหัสที่หลาย ๆ เธรดสามารถเข้าถึงตัวแปรเดียวกันได้อย่างปลอดภัย

ลึก

ไวยากรณ์ฉลาดsynchronizedคำหลักที่ใช้เวลาObjectเป็นมันของพารามิเตอร์ (เรียกว่าวัตถุล็อค ) { block of code }ซึ่งเป็นไปแล้วด้วย

  • เมื่อการดำเนินการพบคำหลักนี้เธรดปัจจุบันพยายามที่จะ "ล็อค / รับ / เป็นเจ้าของ" (เลือกของคุณ) วัตถุล็อคและดำเนินการบล็อกที่เกี่ยวข้องของรหัสหลังจากที่ได้รับล็อค

  • เขียนใด ๆ กับตัวแปรภายในรหัสบล็อกตรงกันจะรับประกันว่าจะสามารถมองเห็นได้ในทุกหัวข้ออื่น ๆ ที่ใกล้เคียงกันรันรหัสภายในการป้องกันรหัสตรงกันใช้เดียวกันวัตถุล็อค

  • แต่ละเธรดสามารถล็อคได้ครั้งละหนึ่งเธรดเท่านั้นในระหว่างนั้นเธรดอื่น ๆ ทั้งหมดที่พยายามรับวัตถุล็อคเดียวกันจะรอ (หยุดการทำงานชั่วคราว) ล็อคจะได้รับการปล่อยตัวเมื่อการดำเนินการออกจากบล็อกรหัสที่ซิงโครไนซ์

วิธีการซิงโครไนซ์:

เพิ่มsynchronizedคำหลักคำนิยามวิธีการที่จะมีค่าเท่ากับร่างกายวิธีการทั้งหมดถูกห่อในการป้องกันรหัสตรงกับวัตถุล็อคเป็นอยู่this (สำหรับวิธีการเป็นต้น)และ(สำหรับวิธีการเรียน)ClassInQuestion.getClass()

- วิธีอินสแตนซ์เป็นวิธีที่ไม่มีstaticคำหลัก
- วิธีการเรียนเป็นวิธีการที่มีstaticคำหลัก

วิชาการ

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

ไม่เพียงพอที่จะดำเนินการเขียนในเธรดก่อน (เวลานาฬิกาผนัง) อ่านเธรดอื่นเนื่องจากฮาร์ดแวร์สามารถแคชค่าของตัวแปรได้และเธรดการอ่านจะเห็นค่าแคชแทนสิ่งที่ถูกเขียนไป มัน.

ข้อสรุป

ดังนั้นในกรณีของ Java คุณต้องติดตาม Java Memory Model เพื่อให้แน่ใจว่าข้อผิดพลาดการทำเกลียวไม่เกิดขึ้น
กล่าวอีกนัยหนึ่ง: ใช้การซิงโครไนซ์การดำเนินการปรมาณูหรือคลาสที่ใช้สำหรับคุณภายใต้ประทุน

แหล่งที่มา

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
ข้อมูลจำเพาะภาษาJava®, 2015-02-13


ขออภัยฉันมีตัวอย่างนี้และฉันไม่เข้าใจความหมาย: `Integer i1 = Arrays.asList (1,2,3,4,5) .stream (). findAny (). get (); ทำข้อมูลให้ตรงกัน (i1) {จำนวนเต็ม i2 = Arrays.asList (6,7,8,9,10) .parallelStream () .sorted () .findAny (). get (); System.out.println (i1 + "" + i2); } `1. เหตุใดคุณจึงเรียกใช้บล็อกในอินสแตนซ์แรกและการเรียกใช้นี้ไม่มีผลกับโค้ด? 2. อินสแตนซ์ที่สองจะเป็นเธรดที่ปลอดภัยแม้จะมีการเรียกใช้บล็อกในครั้งแรกหรือไม่
Adryr83

1
@ Adryr83 หากคุณมีคำถามคุณอาจถามโดยโพสต์คำถามใหม่ แต่เนื่องจากเราอยู่ที่นี่ฉันจะแยกวิเคราะห์สิ่งที่ฉันสามารถทำได้ (คำถามของคุณค่อนข้างยากที่จะเข้าใจ) จากสิ่งที่ฉันสามารถบอกเกี่ยวกับชิ้นส่วนของรหัสนั้นดูเหมือนจะไม่มีสิ่งใดที่ต้องการการซิงโครไนซ์ มันอยู่นอกบริบท คำแนะนำ: หากทำได้ให้ลองแบ่งรหัสเป็นชิ้นเล็ก ๆ แล้วค้นหาคำตอบเกี่ยวกับสิ่งเหล่านั้น การพยายามเข้าใจปัญหาเล็ก ๆ น้อย ๆ และแยกได้ง่ายกว่าการพยายามคิดรหัสใหญ่ ๆ หนึ่งบล็อก
Gima

21

คิดว่ามันเป็นประตูหมุนแบบที่คุณอาจพบในสนามฟุตบอล มีผู้คนจำนวนมากที่ต้องการเข้ามา แต่เมื่อถึงจุดหมุนพวกเขาก็จะ 'ซิงโครไนซ์' สามารถผ่านได้ครั้งละหนึ่งคนเท่านั้น ผู้ที่ต้องการผ่านจะทำ แต่พวกเขาอาจต้องรอจนกว่าจะผ่าน


16

คำหลักที่ตรงกันคืออะไร

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

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

เมื่อใดที่วิธีการทำข้อมูลให้ตรงกัน?

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

โปรหมายความว่าในทางไวยากรณ์และเหตุผล?

หมายความว่ามีเพียงหนึ่งเธรดเท่านั้นที่สามารถเข้าถึงส่วนที่สำคัญโดยการรับการล็อก นอกจากว่าเธรดนี้จะปล่อยการล็อกนี้เธรดอื่น ๆ ทั้งหมดจะต้องรอรับการล็อค พวกเขาไม่สามารถเข้าถึงส่วนสำคัญโดยไม่ต้องมีการล็อค

สิ่งนี้ไม่สามารถทำได้ด้วยเวทมนต์ เป็นความรับผิดชอบของโปรแกรมเมอร์ในการระบุส่วนที่สำคัญในใบสมัครและป้องกันตามนั้น Java จัดเตรียมเฟรมเวิร์กเพื่อปกป้องแอ็พพลิเคชันของคุณ แต่ที่ไหนและทุกส่วนที่ต้องป้องกันเป็นความรับผิดชอบของโปรแกรมเมอร์

รายละเอียดเพิ่มเติมจากหน้าเอกสาร Java

Intrinsic Locks และการซิงโครไนซ์:

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

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

มีการกล่าวถึงเธรดเพื่อให้เป็นเจ้าของการล็อคที่แท้จริงระหว่างเวลาที่ได้รับการล็อคและปลดล็อค ตราบใดที่เธรดเป็นเจ้าของการล็อคที่แท้จริงไม่มีเธรดอื่นสามารถรับการล็อคเดียวกัน เธรดอื่นจะบล็อกเมื่อพยายามรับการล็อก

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

ทำให้วิธีการทำข้อมูลให้ตรงกันมีสองผล :

ครั้งแรกเป็นไปไม่ได้สำหรับการเรียกใช้วิธีการซิงโครไนซ์สองครั้งบนวัตถุเดียวกันเพื่อแทรกสอด

เมื่อเธรดหนึ่งกำลังดำเนินการวิธีการซิงโครไนซ์สำหรับวัตถุเธรดอื่นทั้งหมดที่เรียกใช้วิธีการซิงโครไนส์สำหรับบล็อกวัตถุเดียวกัน (ระงับการดำเนินการ) จนกระทั่งเธรดแรกเสร็จสิ้นกับวัตถุ

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

สิ่งนี้รับประกันว่าการเปลี่ยนแปลงสถานะของวัตถุสามารถมองเห็นได้กับกระทู้ทั้งหมด

ค้นหาทางเลือกอื่นเพื่อซิงโครไนซ์ใน:

หลีกเลี่ยงการซิงโครไนซ์ (นี่) ใน Java หรือไม่


11

Synchronized normal methodเทียบเท่ากับ Synchronized statement(ใช้สิ่งนี้)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized static methodเทียบเท่ากับSynchronized statement(ใช้คลาส)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

คำสั่งที่ประสาน (ใช้ตัวแปร)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

สำหรับsynchronizedเรามีทั้งสองและSynchronized Methods Synchronized Statementsแต่Synchronized Methodsมีความคล้ายคลึงกับเพื่อให้เราเพียงแค่ต้องเข้าใจSynchronized StatementsSynchronized Statements

=> โดยทั่วไปเราจะมี

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

นี่คือ 2 คิดว่าช่วยให้เข้าใจ synchronized

  • วัตถุ / คลาสทุกอันintrinsic lockเกี่ยวข้องกับมัน
  • เมื่อด้ายจะเรียกsynchronized statementมันจะได้มาซึ่งintrinsic lockการที่synchronized statement'sวัตถุและปล่อยมันเมื่อวิธีการผลตอบแทน ตราบใดที่ด้ายเป็นเจ้าของintrinsic lock, NO อื่น ๆด้ายสามารถได้รับเดียวกันล็อค => ปลอดภัยด้าย

=> เมื่อผู้thread Aเรียกใช้synchronized(this){// code 1}=> รหัสบล็อกทั้งหมด (ภายในคลาส) ที่มีsynchronized(this)และทั้งหมดsynchronized normal method(ภายในคลาส) ถูกล็อคเนื่องจากการล็อกเดียวกัน มันจะทำงานหลังจากthread Aปลดล็อค ("// code 1" เสร็จสิ้น)

พฤติกรรมนี้จะคล้ายกับหรือ synchronized(a variable){// code 1}synchronized(class)

SAME LOCK => lock (ไม่ขึ้นอยู่กับวิธีการใดหรือคำสั่งใด?)

ใช้วิธีการซิงโครไนซ์หรือคำสั่งที่ซิงโครไนซ์หรือไม่

ฉันชอบsynchronized statementsเพราะมันยืดได้มากกว่า ตัวอย่างในอนาคตคุณจะต้องซิงโครไนซ์ส่วนหนึ่งของวิธีการเท่านั้น ตัวอย่างคุณมีวิธีการซิงโครไนซ์ 2 วิธีและไม่มีความเกี่ยวข้องกันอย่างไรก็ตามเมื่อเธรดรันเมธอดเมธอดจะบล็อกเมธอดอื่น (สามารถป้องกันได้โดยการใช้งานsynchronized(a variable))

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

บันทึก

(มันไม่เกี่ยวข้องกับสิ่งที่มากถึงsynchronizedมันเป็นความแตกต่างระหว่างวัตถุและคลาสหรือไม่มีแบบคงที่และแบบคงที่)

  • เมื่อคุณใช้synchronizedหรือวิธีการปกติsynchronized(this)หรือsynchronized(non-static variable)มันจะทำข้อมูลให้ตรงกันฐานในแต่ละวัตถุเช่น
  • เมื่อคุณใช้synchronizedหรือวิธีการแบบคงที่หรือsynchronized(class)หรือsynchronized(static variable)มันจะประสานฐานในชั้นเรียน

การอ้างอิง

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

หวังว่ามันจะช่วย


11

นี่คือคำอธิบายจากจาวาสอน

พิจารณารหัสต่อไปนี้:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

ถ้าcountเป็นตัวอย่างของSynchronizedCounterการทำวิธีการเหล่านี้ให้ตรงกันมีสองผล:

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

9

ความเข้าใจของฉันตรงกันโดยทั่วไปหมายความว่าคอมไพเลอร์เขียน monitor.enter และ monitor.exit รอบวิธีการของคุณ เช่นนี้อาจเป็นเธรดที่ปลอดภัยขึ้นอยู่กับวิธีการใช้งาน (สิ่งที่ฉันหมายถึงคือคุณสามารถเขียนวัตถุด้วยวิธีการซิงโครไนซ์ที่ไม่ได้เป็น threadsafe ขึ้นอยู่กับสิ่งที่ชั้นเรียนของคุณทำ)


5

อะไรคำตอบอื่น ๆ จะหายไปเป็นหนึ่งในสิ่งสำคัญ: ปัญหาและอุปสรรคที่หน่วยความจำ การซิงโครไนซ์เธรดโดยทั่วไปประกอบด้วยสองส่วนคือการทำให้เป็นอนุกรมและการมองเห็น ฉันแนะนำให้ทุกคนใช้ google สำหรับ "อุปสรรคหน่วยความจำ jvm" เนื่องจากเป็นหัวข้อที่ไม่สำคัญและสำคัญมาก (หากคุณแก้ไขข้อมูลที่แบ่งปันซึ่งเข้าถึงได้โดยหลายเธรด) หลังจากทำอย่างนั้นแล้วฉันแนะนำให้ดูคลาสของแพ็คเกจ java.util.concurrent ที่ช่วยหลีกเลี่ยงการใช้การซิงโครไนซ์อย่างชัดเจนซึ่งจะช่วยให้โปรแกรมเรียบง่ายและมีประสิทธิภาพอาจป้องกันการหยุดชะงัก

ตัวอย่างหนึ่งคือConcurrentLinkedDeque ร่วมกับรูปแบบคำสั่งที่อนุญาตให้สร้างเธรดผู้ปฏิบัติงานที่มีประสิทธิภาพสูงโดยการบรรจุคำสั่งลงในคิวที่เกิดขึ้นพร้อมกัน - ไม่จำเป็นต้องซิงโครไนซ์อย่างชัดเจน, ไม่มีการหยุดชะงักที่เป็นไปได้, ไม่จำเป็นต้องสลีปอย่างชัดเจน

ในระยะสั้น: "การซิงโครไนซ์หน่วยความจำ" เกิดขึ้นโดยปริยายเมื่อคุณเริ่มเธรดเธรดสิ้นสุดคุณอ่านตัวแปรระเหยคุณปลดล็อกจอภาพ (ปล่อยให้บล็อก / ฟังก์ชันที่ซิงโครไนซ์) เป็นต้นการซิงโครไนซ์ ") การเขียนทั้งหมดเสร็จสิ้นก่อนการกระทำเฉพาะนั้น ในกรณีของConcurrentLinkedDequeดังกล่าวข้างต้นเอกสาร "พูดว่า":

เอฟเฟกต์ความสอดคล้องของหน่วยความจำ: เช่นเดียวกับคอลเลกชันอื่น ๆ ที่เกิดขึ้นพร้อมกันการดำเนินการในเธรดก่อนที่จะวางวัตถุลงใน ConcurrentLinkedDeque เกิดขึ้นก่อนการดำเนินการภายหลังการเข้าถึงหรือกำจัดองค์ประกอบนั้นออกจาก ConcurrentLinkedDeque

พฤติกรรมโดยนัยนี้เป็นลักษณะที่ค่อนข้างอันตรายเนื่องจากโปรแกรมเมอร์ Java ส่วนใหญ่ที่ไม่มีประสบการณ์มากจะใช้เวลามากตามที่กำหนดเพราะมัน และทันใดนั้นก็สะดุดกับหัวข้อนี้หลังจาก Java ไม่ได้ทำในสิ่งที่ "ควร" ในการผลิตที่มีภาระงานที่แตกต่าง - และมันยากที่จะทดสอบปัญหาการทำงานพร้อมกัน


3

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

class MyRunnable implements Runnable {
    int var = 10;
    @Override
    public void run() {
        call();
    }

    public void call() {
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                var++;
                System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var);
            }
        }
    }
}

public class MutlipleThreadsRunnable {
    public static void main(String[] args) {
        MyRunnable runnable1 = new MyRunnable();
        MyRunnable runnable2 = new MyRunnable();
        Thread t1 = new Thread(runnable1);
        t1.setName("Thread -1");
        Thread t2 = new Thread(runnable2);
        t2.setName("Thread -2");
        Thread t3 = new Thread(runnable1);
        t3.setName("Thread -3");
        t1.start();
        t2.start();
        t3.start();
    }
}

เราได้สร้างวัตถุคลาส MyRunnable สองอัน runnable1 กำลังแชร์กับเธรด 1 และเธรด 3 & runnable2 ที่แชร์กับเธรด 2 เท่านั้น ตอนนี้เมื่อ t1 และ t3 เริ่มต้นโดยไม่ต้องซิงโครไนซ์เอาต์พุต PFB ซึ่งแนะนำว่าทั้งเธรด 1 และ 3 จะมีผลต่อค่า var ที่เธรด 2 สำหรับเธรด 2 พร้อมกัน var มีหน่วยความจำของตัวเอง

Without Synchronized keyword

    Current Thread Thread -1 var value 11
    Current Thread Thread -2 var value 11
    Current Thread Thread -2 var value 12
    Current Thread Thread -2 var value 13
    Current Thread Thread -2 var value 14
    Current Thread Thread -1 var value 12
    Current Thread Thread -3 var value 13
    Current Thread Thread -3 var value 15
    Current Thread Thread -1 var value 14
    Current Thread Thread -1 var value 17
    Current Thread Thread -3 var value 16
    Current Thread Thread -3 var value 18

ใช้ Synchronzied, เธรด 3 กำลังรอเธรด 1 ให้เสร็จสมบูรณ์ในทุกสถานการณ์ มีการล็อกสองรายการที่ได้รับหนึ่งรายการใน runnable1 ที่แชร์โดยเธรด 1 และเธรด 3 และอีกหนึ่งรายการใน runnable2 ที่แบ่งปันโดยเธรด 2 เท่านั้น

Current Thread Thread -1 var value 11
Current Thread Thread -2 var value 11
Current Thread Thread -1 var value 12
Current Thread Thread -2 var value 12
Current Thread Thread -1 var value 13
Current Thread Thread -2 var value 13
Current Thread Thread -1 var value 14
Current Thread Thread -2 var value 14
Current Thread Thread -3 var value 15
Current Thread Thread -3 var value 16
Current Thread Thread -3 var value 17
Current Thread Thread -3 var value 18

การซิงโครไนซ์หมายถึงยิ่งไปกว่านั้นมันมีผลกระทบอย่างลึกซึ้งต่อสิ่งกีดขวางหน่วยความจำ
user1050755

1

เรียบง่ายแบบซิงโครไนซ์หมายความว่าไม่มีสองเธรดที่สามารถเข้าถึงบล็อก / วิธีการพร้อมกัน เมื่อเราบอกว่ามีการซิงโครไนซ์บล็อก / วิธีใด ๆ ของคลาสหมายความว่ามีเพียงเธรดเดียวเท่านั้นที่สามารถเข้าถึงได้ในแต่ละครั้ง ภายในเธรดที่พยายามเข้าถึงนั้นจะใช้การล็อกบนวัตถุนั้นก่อนและตราบใดที่การล็อกนี้ไม่พร้อมใช้งานไม่มีเธรดอื่นสามารถเข้าถึงวิธีการ / บล็อกที่ซิงโครไนซ์ของอินสแตนซ์ของคลาสนั้นได้

หมายเหตุเธรดอื่นสามารถเข้าถึงวิธีการของวัตถุเดียวกันซึ่งไม่ได้กำหนดให้ซิงโครไนซ์ เธรดสามารถปลดล็อกได้โดยการเรียก

Object.wait()

0

synchronizedบล็อกใน Java เป็นจอภาพในมัลติเธรด synchronizedบล็อกที่มีวัตถุ / คลาสเดียวกันสามารถดำเนินการได้โดยเธรดเดียวเท่านั้นส่วนอื่น ๆ ทั้งหมดกำลังรออยู่ มันสามารถช่วยในrace conditionสถานการณ์เมื่อหลายกระทู้พยายามที่จะปรับปรุงตัวแปรเดียวกัน (ขั้นตอนแรกคือการใช้volatileเกี่ยวกับ )

Java 5ขยายsynchronizedโดยการสนับสนุนhappens-before[เกี่ยวกับ]

การปลดล็อค (บล็อกที่ถูกซิงโครไนซ์หรือออกจากเมธอด) ของจอภาพเกิดขึ้นก่อนการล็อคครั้งต่อไป

ขั้นตอนต่อไปคือ java.util.concurrent

ระเหยกับซิงโครไนซ์


-6

ทำข้อมูลให้ตรงกันเป็นคำหลักใน Java ที่ใช้ในการเกิดขึ้นก่อนที่ความสัมพันธ์ในสภาพแวดล้อมแบบมัลติเธรดเพื่อหลีกเลี่ยงความไม่สอดคล้องกันของหน่วยความจำและข้อผิดพลาดการรบกวนด้าย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.