ฉันมีคำถามบางอย่างเกี่ยวกับการใช้งานและความสำคัญของsynchronized
คำหลัก
- คำสำคัญของ
synchronized
คำสำคัญคืออะไร - วิธีการควรเป็นเมื่อไหร่
synchronized
? - มันหมายถึงอะไรโดยทางโปรแกรมและเหตุผล?
ฉันมีคำถามบางอย่างเกี่ยวกับการใช้งานและความสำคัญของsynchronized
คำหลัก
synchronized
คำสำคัญคืออะไรsynchronized
?คำตอบ:
synchronized
คำหลักคือทั้งหมดที่เกี่ยวกับหัวข้อที่แตกต่างกันอ่านและการเขียนตัวแปรเดียวกันวัตถุและทรัพยากร นี่ไม่ใช่หัวข้อเล็กน้อยใน Java แต่นี่เป็นคำพูดจาก Sun:
synchronized
เมธอดเปิดใช้งานกลยุทธ์อย่างง่ายสำหรับการป้องกันเธรดการรบกวนและข้อผิดพลาดที่สอดคล้องกันของหน่วยความจำ: หากวัตถุปรากฏให้เห็นมากกว่าหนึ่งเธรดการอ่านหรือเขียนทั้งหมดไปยังตัวแปรของวัตถุนั้นทำได้ด้วยวิธีการซิงโครไนซ์
โดยสรุปแล้วมีขนาดเล็กมาก:เมื่อคุณมีสองเธรดที่อ่านและเขียนไปยัง 'ทรัพยากร' เดียวกันพูดชื่อตัวแปรfoo
คุณต้องแน่ใจว่าเธรดเหล่านี้เข้าถึงตัวแปรในวิธีอะตอมมิก หากไม่มีsynchronized
คำหลักเธรด 1 ของคุณอาจไม่เห็นเธรดการเปลี่ยนแปลง 2 ที่ทำขึ้นfoo
หรือแย่ลงมันอาจเปลี่ยนไปเพียงครึ่งเดียว นี่จะไม่ใช่สิ่งที่คุณคาดหวังอย่างมีเหตุผล
อีกครั้งนี่เป็นหัวข้อที่ไม่สำคัญใน Java หากต้องการเรียนรู้เพิ่มเติมสำรวจหัวข้อที่นี่ใน SO และ Interwebs เกี่ยวกับ:
สำรวจหัวข้อเหล่านี้ต่อไปจนกว่าชื่อ"Brian Goetz"จะเชื่อมโยงอย่างถาวรกับคำว่า"การเกิดพร้อมกัน"ในสมองของคุณ
ฉันคิดว่าเรามีคำอธิบายทางทฤษฎีเพียงพอแล้วดังนั้นให้พิจารณารหัสนี้
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
synchronized
แต่ความสอดคล้องของหน่วยความจำจะถูกละเว้น
synchronized
คำหลักที่จะช่วยป้องกันการเข้าถึงพร้อมกันไปยังบล็อกของรหัสหรือวัตถุจากหลายกระทู้ วิธีการทั้งหมดHashtable
เป็นsynchronized
ดังนั้นเพียงหนึ่งเธรดสามารถดำเนินการใด ๆ ของพวกเขาในเวลา
เมื่อใช้synchronized
งานที่ไม่ใช่โครงสร้างHashMap
คุณต้องสร้างคุณสมบัติความปลอดภัยของเธรดในรหัสของคุณเพื่อป้องกันข้อผิดพลาดที่สอดคล้องกัน
synchronized
หมายความว่าในสภาพแวดล้อมแบบมัลติเธรดวัตถุที่มี synchronized
วิธีการ / บล็อก (s) จะไม่ปล่อยให้สองเธรดเข้าถึงsynchronized
วิธี / บล็อก (s) ของรหัสในเวลาเดียวกัน ซึ่งหมายความว่าหนึ่งเธรดไม่สามารถอ่านได้ในขณะที่เธรดอื่นอัปเดต
เธรดที่สองจะรอจนกว่าเธรดแรกจะเสร็จสิ้นการดำเนินการ ค่าใช้จ่ายคือความเร็ว แต่ข้อดีคือรับประกันความสอดคล้องของข้อมูล
หากแอปพลิเคชันของคุณเป็นเธรดเดี่ยวแม้ว่าsynchronized
บล็อกจะไม่ให้ประโยชน์
synchronized
คำหลักที่ทำให้เกิดด้ายเพื่อให้ได้ล็อคเมื่อเข้าสู่วิธีการเพื่อให้มีเพียงหนึ่งหัวข้อสามารถดำเนินการวิธีการในเวลาเดียวกัน (เช่นวัตถุที่กำหนดเว้นแต่จะเป็นวิธีการคงที่)
สิ่งนี้มักถูกเรียกว่าการทำให้คลาสของเธรดปลอดภัย แต่ฉันจะบอกว่านี่เป็นคำสละสลวย แม้ว่าจะเป็นความจริงที่การซิงโครไนซ์จะป้องกันสถานะภายในของ Vector จากการได้รับความเสียหาย แต่ก็ไม่ได้ช่วยผู้ใช้ Vector มากนัก
พิจารณาสิ่งนี้:
if (vector.isEmpty()){
vector.add(data);
}
แม้ว่าเมธอดที่เกี่ยวข้องจะถูกซิงโครไนซ์เนื่องจากพวกเขากำลังถูกล็อกและปลดล็อกทีละเธรดเธรดที่หมดเวลาสองเธรดสามารถสร้างเวกเตอร์ที่มีสองอิลิเมนต์
ดังนั้นคุณต้องซิงโครไนซ์ในรหัสแอปพลิเคชันของคุณด้วย
เนื่องจากการซิงโครไนซ์ระดับวิธีการ a) แพงเมื่อคุณไม่ต้องการและ b) ไม่เพียงพอเมื่อคุณต้องการการซิงโครไนซ์ตอนนี้มีการแทนที่ที่ไม่ซิงโครไนซ์ (ArrayList ในกรณีของ Vector)
เมื่อไม่นานมานี้แพ็คเกจการทำงานพร้อมกันได้รับการเผยแพร่พร้อมกับยูทิลิตี้ที่ชาญฉลาดจำนวนมากที่ดูแลปัญหาการเธรดหลายเธรด
คีย์เวิร์ดที่ซิงโครไนซ์ใน 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
คิดว่ามันเป็นประตูหมุนแบบที่คุณอาจพบในสนามฟุตบอล มีผู้คนจำนวนมากที่ต้องการเข้ามา แต่เมื่อถึงจุดหมุนพวกเขาก็จะ 'ซิงโครไนซ์' สามารถผ่านได้ครั้งละหนึ่งคนเท่านั้น ผู้ที่ต้องการผ่านจะทำ แต่พวกเขาอาจต้องรอจนกว่าจะผ่าน
คำหลักที่ตรงกันคืออะไร
หัวข้อการสื่อสารเป็นหลักโดยการแบ่งปันการเข้าถึงไปยังเขตข้อมูลและการอ้างอิงวัตถุฟิลด์อ้างถึง รูปแบบของการสื่อสารนี้จะมีประสิทธิภาพมาก แต่ทำให้สองชนิดของข้อผิดพลาดที่เป็นไปได้: รบกวนด้ายและข้อผิดพลาดของหน่วยความจำสอดคล้อง เครื่องมือที่จำเป็นในการป้องกันข้อผิดพลาดคือการซิงโครไนซ์
การซิงโครไนซ์บล็อกหรือวิธีการป้องกันการรบกวนเธรดและตรวจสอบให้แน่ใจว่าข้อมูลสอดคล้องกัน ณ เวลาใดเวลาหนึ่งเธรดเดียวเท่านั้นที่สามารถเข้าถึงบล็อกหรือวิธีการซิงโครไนซ์ ( ส่วนที่สำคัญ ) ได้โดยการล็อก หัวข้ออื่น ๆ (s) จะรอการเปิดตัวของล็อคเพื่อเข้าถึงส่วนที่สำคัญ
เมื่อใดที่วิธีการทำข้อมูลให้ตรงกัน?
วิธีการที่มีการทำข้อมูลให้ตรงกันเมื่อคุณเพิ่มsynchronized
คำนิยามวิธีการหรือประกาศ นอกจากนี้คุณยังสามารถซิงโครไนซ์บล็อกรหัสเฉพาะกับวิธีในได้
โปรหมายความว่าในทางไวยากรณ์และเหตุผล?
หมายความว่ามีเพียงหนึ่งเธรดเท่านั้นที่สามารถเข้าถึงส่วนที่สำคัญโดยการรับการล็อก นอกจากว่าเธรดนี้จะปล่อยการล็อกนี้เธรดอื่น ๆ ทั้งหมดจะต้องรอรับการล็อค พวกเขาไม่สามารถเข้าถึงส่วนสำคัญโดยไม่ต้องมีการล็อค
สิ่งนี้ไม่สามารถทำได้ด้วยเวทมนต์ เป็นความรับผิดชอบของโปรแกรมเมอร์ในการระบุส่วนที่สำคัญในใบสมัครและป้องกันตามนั้น Java จัดเตรียมเฟรมเวิร์กเพื่อปกป้องแอ็พพลิเคชันของคุณ แต่ที่ไหนและทุกส่วนที่ต้องป้องกันเป็นความรับผิดชอบของโปรแกรมเมอร์
รายละเอียดเพิ่มเติมจากหน้าเอกสาร Java
Intrinsic Locks และการซิงโครไนซ์:
การซิงโครไนซ์ถูกสร้างขึ้นรอบ ๆ เอนทิตีภายในที่เรียกว่าการล็อคภายในหรือการล็อคจอภาพ การล็อคที่แท้จริงมีบทบาทในการซิงโครไนซ์ทั้งสองด้าน: บังคับใช้การเข้าถึงสถานะของวัตถุและสร้างความสัมพันธ์ก่อนเกิดขึ้นซึ่งจำเป็นต่อการมองเห็น
วัตถุทุกคนมีล็อคภายในที่เกี่ยวข้องกับมัน โดยการประชุมเธรดที่ต้องการการเข้าถึงแบบเอกสิทธิ์เฉพาะบุคคลและสอดคล้องกับเขตข้อมูลของวัตถุจะต้องได้รับการล็อคที่แท้จริงของวัตถุก่อนที่จะเข้าถึงพวกเขาแล้วปล่อยล็อคที่แท้จริงเมื่อมันทำกับพวกเขา
มีการกล่าวถึงเธรดเพื่อให้เป็นเจ้าของการล็อคที่แท้จริงระหว่างเวลาที่ได้รับการล็อคและปลดล็อค ตราบใดที่เธรดเป็นเจ้าของการล็อคที่แท้จริงไม่มีเธรดอื่นสามารถรับการล็อคเดียวกัน เธรดอื่นจะบล็อกเมื่อพยายามรับการล็อก
เมื่อเธรดปล่อยการล็อกที่แท้จริงความสัมพันธ์แบบเกิดขึ้นก่อนจะถูกสร้างขึ้นระหว่างการดำเนินการนั้นกับการได้มาของการล็อคเดียวกัน
ทำให้วิธีการทำข้อมูลให้ตรงกันมีสองผล :
ครั้งแรกเป็นไปไม่ได้สำหรับการเรียกใช้วิธีการซิงโครไนซ์สองครั้งบนวัตถุเดียวกันเพื่อแทรกสอด
เมื่อเธรดหนึ่งกำลังดำเนินการวิธีการซิงโครไนซ์สำหรับวัตถุเธรดอื่นทั้งหมดที่เรียกใช้วิธีการซิงโครไนส์สำหรับบล็อกวัตถุเดียวกัน (ระงับการดำเนินการ) จนกระทั่งเธรดแรกเสร็จสิ้นกับวัตถุ
ประการที่สองเมื่อเมธอดซิงโครไนซ์ออกแล้วมันจะสร้างความสัมพันธ์ที่เกิดขึ้นก่อนโดยอัตโนมัติกับการเรียกใช้เมธอดซิงโครไนซ์ที่ตามมาสำหรับวัตถุเดียวกัน
สิ่งนี้รับประกันว่าการเปลี่ยนแปลงสถานะของวัตถุสามารถมองเห็นได้กับกระทู้ทั้งหมด
ค้นหาทางเลือกอื่นเพื่อซิงโครไนซ์ใน:
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 Statements
Synchronized 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
หวังว่ามันจะช่วย
พิจารณารหัสต่อไปนี้:
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
การทำวิธีการเหล่านี้ให้ตรงกันมีสองผล:
- ครั้งแรกเป็นไปไม่ได้สำหรับการเรียกใช้วิธีการซิงโครไนซ์สองครั้งบนวัตถุเดียวกันเพื่อแทรกสอด เมื่อเธรดหนึ่งกำลังดำเนินการวิธีการซิงโครไนซ์สำหรับวัตถุเธรดอื่นทั้งหมดที่เรียกใช้วิธีการซิงโครไนส์สำหรับบล็อกวัตถุเดียวกัน (ระงับการดำเนินการ) จนกระทั่งเธรดแรกเสร็จสิ้นกับวัตถุ
- ประการที่สองเมื่อเมธอดซิงโครไนซ์ออกแล้วมันจะสร้างความสัมพันธ์ที่เกิดขึ้นก่อนโดยอัตโนมัติกับการเรียกใช้เมธอดซิงโครไนซ์ที่ตามมาสำหรับวัตถุเดียวกัน สิ่งนี้รับประกันว่าการเปลี่ยนแปลงสถานะของวัตถุสามารถมองเห็นได้กับกระทู้ทั้งหมด
ความเข้าใจของฉันตรงกันโดยทั่วไปหมายความว่าคอมไพเลอร์เขียน monitor.enter และ monitor.exit รอบวิธีการของคุณ เช่นนี้อาจเป็นเธรดที่ปลอดภัยขึ้นอยู่กับวิธีการใช้งาน (สิ่งที่ฉันหมายถึงคือคุณสามารถเขียนวัตถุด้วยวิธีการซิงโครไนซ์ที่ไม่ได้เป็น threadsafe ขึ้นอยู่กับสิ่งที่ชั้นเรียนของคุณทำ)
อะไรคำตอบอื่น ๆ จะหายไปเป็นหนึ่งในสิ่งสำคัญ: ปัญหาและอุปสรรคที่หน่วยความจำ การซิงโครไนซ์เธรดโดยทั่วไปประกอบด้วยสองส่วนคือการทำให้เป็นอนุกรมและการมองเห็น ฉันแนะนำให้ทุกคนใช้ google สำหรับ "อุปสรรคหน่วยความจำ jvm" เนื่องจากเป็นหัวข้อที่ไม่สำคัญและสำคัญมาก (หากคุณแก้ไขข้อมูลที่แบ่งปันซึ่งเข้าถึงได้โดยหลายเธรด) หลังจากทำอย่างนั้นแล้วฉันแนะนำให้ดูคลาสของแพ็คเกจ java.util.concurrent ที่ช่วยหลีกเลี่ยงการใช้การซิงโครไนซ์อย่างชัดเจนซึ่งจะช่วยให้โปรแกรมเรียบง่ายและมีประสิทธิภาพอาจป้องกันการหยุดชะงัก
ตัวอย่างหนึ่งคือConcurrentLinkedDeque ร่วมกับรูปแบบคำสั่งที่อนุญาตให้สร้างเธรดผู้ปฏิบัติงานที่มีประสิทธิภาพสูงโดยการบรรจุคำสั่งลงในคิวที่เกิดขึ้นพร้อมกัน - ไม่จำเป็นต้องซิงโครไนซ์อย่างชัดเจน, ไม่มีการหยุดชะงักที่เป็นไปได้, ไม่จำเป็นต้องสลีปอย่างชัดเจน
ในระยะสั้น: "การซิงโครไนซ์หน่วยความจำ" เกิดขึ้นโดยปริยายเมื่อคุณเริ่มเธรดเธรดสิ้นสุดคุณอ่านตัวแปรระเหยคุณปลดล็อกจอภาพ (ปล่อยให้บล็อก / ฟังก์ชันที่ซิงโครไนซ์) เป็นต้นการซิงโครไนซ์ ") การเขียนทั้งหมดเสร็จสิ้นก่อนการกระทำเฉพาะนั้น ในกรณีของConcurrentLinkedDequeดังกล่าวข้างต้นเอกสาร "พูดว่า":
เอฟเฟกต์ความสอดคล้องของหน่วยความจำ: เช่นเดียวกับคอลเลกชันอื่น ๆ ที่เกิดขึ้นพร้อมกันการดำเนินการในเธรดก่อนที่จะวางวัตถุลงใน ConcurrentLinkedDeque เกิดขึ้นก่อนการดำเนินการภายหลังการเข้าถึงหรือกำจัดองค์ประกอบนั้นออกจาก ConcurrentLinkedDeque
พฤติกรรมโดยนัยนี้เป็นลักษณะที่ค่อนข้างอันตรายเนื่องจากโปรแกรมเมอร์ Java ส่วนใหญ่ที่ไม่มีประสบการณ์มากจะใช้เวลามากตามที่กำหนดเพราะมัน และทันใดนั้นก็สะดุดกับหัวข้อนี้หลังจาก Java ไม่ได้ทำในสิ่งที่ "ควร" ในการผลิตที่มีภาระงานที่แตกต่าง - และมันยากที่จะทดสอบปัญหาการทำงานพร้อมกัน
การซิงโครไนซ์ก็หมายความว่าหลายกระทู้ถ้าเกี่ยวข้องกับวัตถุเดียวสามารถป้องกันการอ่านและเขียนสกปรกหากบล็อกที่ตรงกันจะใช้กับวัตถุเฉพาะ เพื่อให้คุณมีความชัดเจนมากขึ้นลองมาตัวอย่าง:
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
เรียบง่ายแบบซิงโครไนซ์หมายความว่าไม่มีสองเธรดที่สามารถเข้าถึงบล็อก / วิธีการพร้อมกัน เมื่อเราบอกว่ามีการซิงโครไนซ์บล็อก / วิธีใด ๆ ของคลาสหมายความว่ามีเพียงเธรดเดียวเท่านั้นที่สามารถเข้าถึงได้ในแต่ละครั้ง ภายในเธรดที่พยายามเข้าถึงนั้นจะใช้การล็อกบนวัตถุนั้นก่อนและตราบใดที่การล็อกนี้ไม่พร้อมใช้งานไม่มีเธรดอื่นสามารถเข้าถึงวิธีการ / บล็อกที่ซิงโครไนซ์ของอินสแตนซ์ของคลาสนั้นได้
หมายเหตุเธรดอื่นสามารถเข้าถึงวิธีการของวัตถุเดียวกันซึ่งไม่ได้กำหนดให้ซิงโครไนซ์ เธรดสามารถปลดล็อกได้โดยการเรียก
Object.wait()
synchronized
บล็อกใน Java เป็นจอภาพในมัลติเธรด synchronized
บล็อกที่มีวัตถุ / คลาสเดียวกันสามารถดำเนินการได้โดยเธรดเดียวเท่านั้นส่วนอื่น ๆ ทั้งหมดกำลังรออยู่ มันสามารถช่วยในrace condition
สถานการณ์เมื่อหลายกระทู้พยายามที่จะปรับปรุงตัวแปรเดียวกัน (ขั้นตอนแรกคือการใช้volatile
เกี่ยวกับ )
Java 5
ขยายsynchronized
โดยการสนับสนุนhappens-before
[เกี่ยวกับ]
การปลดล็อค (บล็อกที่ถูกซิงโครไนซ์หรือออกจากเมธอด) ของจอภาพเกิดขึ้นก่อนการล็อคครั้งต่อไป
ขั้นตอนต่อไปคือ java.util.concurrent
ทำข้อมูลให้ตรงกันเป็นคำหลักใน Java ที่ใช้ในการเกิดขึ้นก่อนที่ความสัมพันธ์ในสภาพแวดล้อมแบบมัลติเธรดเพื่อหลีกเลี่ยงความไม่สอดคล้องกันของหน่วยความจำและข้อผิดพลาดการรบกวนด้าย