ทำไมต้องซิงโครไนซ์เธรด
เนื่องจากเมื่อเรามีหลายเธรดเพื่อเข้าถึงตัวแปรหรือวัตถุในเวลาเดียวกันหากมีทั้งการอ่านและเขียนในเธรดเหล่านี้มันจะทำให้เกิดความสับสนในค่าตัวแปรหรือสถานะวัตถุทำให้เกิดข้อยกเว้นของโปรแกรม ตัวอย่างเช่นหากบัญชีธนาคารดำเนินการโดยสองเธรดในเวลาเดียวกันหนึ่งจะถอน 100 หยวนและอื่น ๆ บันทึก 100 หยวน สมมติว่าบัญชีเดิมมี 0 หยวนจะเกิดอะไรขึ้นถ้าเธรดการถอนและเธรดการออมเกิดขึ้นในเวลาเดียวกัน? หากการถอนเงินไม่สำเร็จยอดเงินในบัญชีคือ 100 หากการถอนเงินสำเร็จแล้วยอดเงินในบัญชีคือ 0 มันยากที่จะอธิบายอย่างชัดเจน ดังนั้นการซิงโครไนซ์แบบมัลติเธรดคือการแก้ปัญหานี้
1. รหัสเมื่อไม่ซิงค์
Bank.java แพ็คเกจ Threadtest; ออก. println (System.currentTimeMillis ()+"บันทึก:"+เงิน);} // ถอนเงินเป็นโมฆะสาธารณะ submoney (เงิน int) {ถ้า (นับ money <0) {system.out.println ("ยอดคงเหลือไม่เพียงพอ" ::::::::::::::::::::::: กระทาน :::::::::::::::); เป็นโมฆะ lookmoney () {system.out (); เธรด tad = เธรดใหม่ (ใหม่ runnable () { @ @ reverride public void run () {// todo วิธีการที่สร้างขึ้นอัตโนมัติในขณะที่ (จริง) {ลอง {thread.sleep (1000);} catch (interruptedexception e) {// TODO Auto -Generated Catch Block E.PrintStackTrace (); เธรด (ใหม่ runnable () {@Override public void run () {// todo วิธีการที่สร้างอัตโนมัติในขณะที่ (จริง) {bank.submoney (100); bank.lookmoney (); system.out.println ("/n "); ลอง {thread.sleep (1000);} catch (interruptedException e) {// toDo บล็อกจับที่สร้างอัตโนมัติ e.printstacktrace ();}}}}); tsub.start (); tad.start () ;
รหัสนั้นง่ายมากฉันจะไม่อธิบาย ฉันสกัดกั้นพวกเขาบางส่วนมันยุ่งมากและฉันไม่เข้าใจการเขียน
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 100
1441790503354 เงินฝาก: 100
ยอดเงินในบัญชี: 100
1441790504354 เงินฝาก: 100
ยอดเงินในบัญชี: 100
1441790504354 Take Out: 100
ยอดเงินในบัญชี: 100
1441790505355 เงินฝาก: 100
ยอดเงินในบัญชี: 100
1441790505355 Take Out: 100
ยอดเงินในบัญชี: 100
2. ใช้รหัสแบบซิงโครนัส
(1) วิธีการซิงโครไนซ์:
มีวิธีการแก้ไขคำหลักที่ซิงโครไนซ์ เนื่องจากแต่ละวัตถุใน Java มีการล็อคในตัวเมื่อแก้ไขวิธีการด้วยคำหลักนี้ล็อคในตัวจะป้องกันวิธีทั้งหมด ก่อนที่จะเรียกวิธีการนี้คุณจะต้องได้รับการล็อคในตัวมิฉะนั้นจะอยู่ในสถานะการปิดกั้น
ธนาคารแก้ไข. java
มาดูผลการทำงาน:
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
1441790837380SAVED: 100
ยอดเงินในบัญชี: 100
1441790838380 Take Out: 100
ยอดเงินในบัญชี: 0
1441790838380SAVED: 100
ยอดเงินในบัญชี: 100
1441790839381 ลบ: 100
ยอดเงินในบัญชี: 0
ฉันรู้สึกว่ามันเข้าใจทันที
หมายเหตุ: คำหลักที่ซิงโครไนซ์ยังสามารถแก้ไขวิธีการคงที่
(2) ซิงโครไนซ์บล็อกรหัส
นั่นคือมีบล็อกคำสั่งที่แก้ไขโดยคำหลักที่ซิงโครไนซ์ บล็อกคำสั่งที่แก้ไขโดยคำหลักนี้จะถูกเพิ่มโดยอัตโนมัติด้วยการล็อคในตัวเพื่อให้ได้การซิงโครไนซ์
Bank.java Code มีดังนี้:
Package Threadtest; System.out.println (System.currentTimeMillis ()+"บันทึก:"+เงิน); .println ("สมดุลไม่เพียงพอ"); {System.out.println ("ยอดคงเหลือในบัญชี:"+นับ);}}
ผลการดำเนินการมีดังนี้:
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
1441791806699SAVED: 100
ยอดเงินในบัญชี: 100
1441791806700 Take Out: 100
ยอดเงินในบัญชี: 0
1441791807699SAVED: 100
ยอดเงินในบัญชี: 100
เอฟเฟกต์คล้ายกับวิธีการ
หมายเหตุ: การซิงโครไนซ์เป็นการดำเนินการที่สูงเกินจริงดังนั้นจึงควรลดเนื้อหาที่ซิงโครไนซ์ โดยปกติแล้วไม่จำเป็นต้องซิงโครไนซ์วิธีทั้งหมดเพียงใช้บล็อกรหัสที่ซิงโครไนซ์เพื่อซิงโครไนซ์รหัสคีย์
(3) ใช้ตัวแปรโดเมนพิเศษ (ระเหย) เพื่อให้ได้ซิงโครไนซ์เธรด
คำหลัก A.Volatile ให้กลไกที่ปราศจากล็อคสำหรับการเข้าถึงตัวแปรโดเมน
b การใช้ความผันผวนเพื่อปรับเปลี่ยนโดเมนนั้นเทียบเท่ากับการบอกเครื่องเสมือนจริงว่าโดเมนอาจได้รับการปรับปรุงโดยเธรดอื่น
c. ดังนั้นทุกครั้งที่คุณใช้ฟิลด์คุณต้องคำนวณใหม่แทนที่จะใช้ค่าในการลงทะเบียน
D.Volatile ไม่ได้ให้การดำเนินการอะตอมใด ๆ และไม่สามารถใช้ในการปรับเปลี่ยนตัวแปรของประเภทสุดท้าย
Bank.java Code มีดังนี้:
Package Threadtest; (System.currentTimemillis () + "บันทึก:" + เงิน); ;} count -= เงิน; " + นับ);}}
ผลการดำเนินงานเป็นอย่างไร?
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 100
1441792010959SAVED: 100
ยอดเงินในบัญชี: 100
1441792011960 Take Out: 100
ยอดเงินในบัญชี: 0
1441792011961SAVED: 100
ยอดเงินในบัญชี: 100
เป็นเพราะฉันไม่เข้าใจอีกแล้วและมันยุ่งอีกแล้วเหรอ? ทำไมถึงเป็นเช่นนี้? เป็นเพราะความผันผวนไม่สามารถรับประกันการทำงานของอะตอมได้ดังนั้นความผันผวนจึงไม่สามารถแทนที่ซิงโครไนซ์ได้ นอกจากนี้ความผันผวนจะจัดระเบียบคอมไพเลอร์เพื่อเพิ่มประสิทธิภาพรหัสดังนั้นหากคุณสามารถใช้งานได้ก็จะไม่สามารถใช้ได้ หลักการของมันคือทุกครั้งที่เธรดต้องการเข้าถึงตัวแปรที่แก้ไขโดยความผันผวนมันจะถูกอ่านจากหน่วยความจำมากกว่าในแคชดังนั้นค่าตัวแปรที่เข้าถึงได้โดยแต่ละเธรดจะเหมือนกัน สิ่งนี้ทำให้มั่นใจได้ว่าการซิงโครไนซ์
(4) ใช้ Reentry Lock เพื่อให้ได้การซิงโครไนซ์เธรด
มีการเพิ่มแพ็คเกจ java.util.concurrent ใหม่ลงใน Javase5.0 เพื่อรองรับการซิงโครไนซ์ คลาส REENTRANTLOCK เป็นล็อคแบบพิเศษที่ใช้ร่วมกันซึ่งใช้อินเทอร์เฟซล็อค
วิธีการทั่วไปของคลาส Reenreantlock คือ:
reentrantlock (): สร้างอินสแตนซ์ reentrantlock reentrantlock
ล็อค (): รับล็อค
ปลดล็อค (): reentrantlock หมายเหตุ: reentrantlock () ยังมีตัวสร้างที่สามารถสร้างล็อคที่เป็นธรรม แต่ไม่แนะนำให้ใช้เพราะสามารถลดประสิทธิภาพการทำงานของโปรแกรมได้อย่างมาก
รหัส Bank.java ได้รับการแก้ไขดังนี้:
แพ็คเกจ threadtest; //คุณจำเป็นต้องประกาศล็อคส่วนตัวล็อค = ใหม่ reentrantlock (); TLN (System .CurrentTimeMillis () + "บันทึก:" + เงิน); if (count - money <0) {system.out.println ("สมดุลไม่เพียงพอ"); ;} ในที่สุด {lock.unlock ();
ผลการดำเนินงานเป็นอย่างไร?
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
1441792891934 เงินฝาก: 100
ยอดเงินในบัญชี: 100
1441792892935SAVED: 100
ยอดเงินในบัญชี: 200
1441792892954 Take Out: 100
ยอดเงินในบัญชี: 100
เอฟเฟกต์คล้ายกับสองวิธีแรก
หากคำหลักที่ซิงโครไนซ์สามารถตอบสนองความต้องการของผู้ใช้ให้ใช้การซิงโครไนซ์เนื่องจากสามารถทำให้รหัสง่ายขึ้น หากคุณต้องการฟังก์ชั่นขั้นสูงให้ใช้คลาส Reentrantlock
(5) ใช้ตัวแปรท้องถิ่นเพื่อให้เกิดการซิงโครไนซ์เธรด
Bank.java Code มีดังนี้:
แพ็คเกจ Threadtest; กลับมา 0; );} // ถอนเงินเป็นโมฆะสาธารณะ submoney (int money) {ถ้า count.get () - เงิน <0) {system.out.println ("ยอดคงเหลือไม่เพียงพอ"); ()- เงิน); นับ.
เอฟเฟกต์การทำงาน:
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
1441794247939SAVED: 100
ยอดเงินในบัญชี: 100
สมดุลไม่เพียงพอ
1441794248940SAVE: 100
ยอดเงินในบัญชี: 0
ยอดเงินในบัญชี: 200
ยอดคงเหลือบัญชียอดคงเหลือไม่เพียงพอ: 0
1441794249941SAVED: 100
ยอดเงินในบัญชี: 300
หลังจากเห็นเอฟเฟกต์การดำเนินการฉันสับสนในตอนแรก ดูหลักการของ Threadlocal:
หากคุณใช้ ThreadLocal เพื่อจัดการตัวแปรแต่ละเธรดที่ใช้ตัวแปรจะได้รับสำเนาของตัวแปรและสำเนานั้นเป็นอิสระจากกันเพื่อให้แต่ละเธรดสามารถแก้ไขสำเนาของตัวแปรของตัวเองได้โดยไม่ส่งผลกระทบต่อเธรดอื่น ๆ ตอนนี้ฉันเข้าใจ ดังนั้นผลข้างต้นจะเกิดขึ้น
กลไก ThreadLocal และ Synchronization
A.ThreadLocal และกลไกการซิงโครไนซ์มีวัตถุประสงค์เพื่อแก้ปัญหาความขัดแย้งการเข้าถึงของตัวแปรเดียวกันในมัลติเธรด
b
ตอนนี้ฉันเข้าใจ แต่ละคนมีข้อได้เปรียบและข้อเสียของตัวเองและมีสถานการณ์ที่เกี่ยวข้อง