มาดูรหัสนี้กันเถอะ:
นำเข้า java.util.bitset; นำเข้า java.util.current.countdownlatch; เธรด t1 = เธรดใหม่ (ใหม่ runnable () {public void run () {ลอง {latch.await (); thread.sleep (1000);} catch (Exception ex) {} bs.set (1);}); เธรด t2 = เธรดใหม่ (ใหม่ runnable () {public void run () {ลอง {latch.await (); thread.sleep (1000);} catch (Exception e) {} bs.set (2);}}) เริ่มต้น (); :}}คำถามคือผลลัพธ์ของเอาต์พุตรหัสนี้คืออะไร? ผลลัพธ์ใดที่สามารถส่งออกได้
มาดูกันว่าโปรแกรมนี้ทำอะไร:
ต่อไปเราต้องสร้างกรณีทดสอบบางกรณีเพื่อตรวจสอบพฤติกรรมเหล่านี้ เห็นได้ชัดว่าหนึ่งในนั้นสามารถเรียกใช้ตัวอย่างนี้ได้เท่านั้นจากนั้นสังเกตผลลัพธ์และตอบคำถามข้างต้น
ความระมัดระวังสามารถสร้างความบังเอิญได้
โชคดีที่เราสามารถใช้เครื่องมือ JCSTress เป็นเครื่องมือทดสอบสำหรับการแก้ปัญหาดังกล่าว
เราสามารถเขียนกรณีทดสอบของเราเป็นแบบฟอร์มที่ JCSTress สามารถจดจำได้ ในความเป็นจริงมันได้เตรียมอินเทอร์เฟซที่หลากหลายสำหรับเรา เราต้องการตัวอย่าง
เราใช้ Actor2_ARBITER1_TEEST <Bitset, BooleanResult2> อินเตอร์เฟส เราจำเป็นต้องหา Java 8 JVM เพื่อเรียกใช้ แต่ตอนนี้นี่ไม่ใช่ปัญหา
ดูการใช้งานด้านล่าง
AnexampleTest คลาสสาธารณะใช้ Actor2_Arbiter1_Test <Bitset, BooleanResult2> {@Override โมฆะสาธารณะนักแสดง 1 (Bitset S, BooleanResult2 R) {S.Set (1);} @Override Void Public Void Actor2 );} @Override โมฆะสาธารณะ Arbiter1 (Bitset S, BooleanResult2 R) {r.r1 = s.get (1); ;} @Override Public Boolenrsult2 newResult () {ส่งคืนใหม่ booleanResult2 ();}}
ตอนนี้เมื่อทำการทดสอบนี้การควบคุมจะลองใช้เทคนิคทุกชนิดเพื่อให้ได้ปัจจัยที่เป็นไปได้ทั้งหมดที่ผลักดันการกระทำเหล่านี้: ขนานหรือไม่ใช่ผู้ที่ไม่ได้ตรวจจับการโหลดและมีหลายครั้งในบรรทัดเดียวหลายครั้งหลายครั้ง หลายครั้งหลายครั้งหลายครั้งดังนั้นผลลัพธ์ที่เป็นไปได้ทั้งหมดจะถูกบันทึก
เมื่อคุณต้องการทราบว่ารหัสคู่ขนานของคุณเปิดอยู่นี่เป็นวิธีที่ดีกว่าในการขุดความคิดกลวงและคิดถึงรายละเอียดทั้งหมดมากกว่าตัวคุณเอง
นอกจากนี้เพื่อใช้ความสะดวกสบายที่ครอบคลุมโดยข้อ จำกัด ของ JCSTress เราจำเป็นต้องให้คำอธิบายเกี่ยวกับผลลัพธ์ที่เป็นไปได้
<test name = "org.openjdk.jcsstress.tests.custom.anexampletest"> <bit-by> Oleg Shelajev </ส่วนสนับสนุน> <คำอธิบายหาก Bitset ทำงานได้ดีกับการซิงโครไนซ์ > การจับคู่> [True, True] </match> <post> ที่ยอมรับได้ </post> <scription> เห็นการอัปเดตทั้งหมดเหมือนเดิม /คาดหวัง> <scription> T2 เขียนทับผลลัพธ์ T1 > </case> <nmatched> <post> Forbidden </exten> <scription> กรณีอื่น ๆ ทั้งหมดอยู่ภายใต้ Unlenexpected
ตอนนี้เราพร้อมสำหรับสัตว์ร้ายนี้ที่จะเริ่มคำราม
java -xx:+unlockdiagnosticvmoptions -xx:+whiteboxapi -xx: -resterictcontended -jar tests -custot/target/jcsstress.jar -t = ".*anexampletest"
ผลลัพธ์ที่เราได้รับคือรายงานที่สง่างาม
เป็นที่ชัดเจนว่าเราไม่เพียง แต่ได้ผลลัพธ์ที่คาดหวังนั่นคือทั้งสองเธรดได้ตั้งค่าตำแหน่งของพวกเขา แต่ยังพบกับสภาพการแข่งขันและหนึ่งเธรดจะครอบคลุมผลลัพธ์ของเธรดอื่น
แม้ว่าคุณจะเห็นสิ่งนี้คุณต้องมีความคิดที่สงบของ "The Mountain People มีลูกเล่นของตัวเอง" ใช่ไหม?
โดยวิธีการถ้าคุณกำลังคิดเกี่ยวกับวิธีการแก้ไขรหัสนี้คำตอบคือการอ่านคลาส Bitset อย่างระมัดระวังใน Javadoc และตระหนักว่ามันไม่ใช่ความปลอดภัยของเธรดและต้องมีการซิงโครไนซ์ภายนอก สิ่งนี้สามารถทำได้อย่างง่ายดายโดยการเพิ่มค่าการตั้งค่าของบล็อกซิงโครนัส
ซิงโครไนซ์ (bs) {bs.set (1);}