ตัวทำซ้ำที่ไม่ปลอดภัยและล้มเหลวใน Java คืออะไร


102

ตัววนซ้ำใน Java มีสองประเภท: fail-safe และ fail-fast

นี่หมายความว่าอย่างไรและความแตกต่างระหว่างพวกเขาคืออะไร?


3
ลิงค์ที่ดีที่สุดที่ฉันพบjavahungry.blogspot.com/2014/04/…
เปรมราช

2
โปรดทราบว่าข้อกำหนด Java SE ไม่ได้ใช้คำว่า "fail-safe" เพื่ออธิบายตัวทำซ้ำใด ๆ ฉันจึงแนะนำให้หลีกเลี่ยงคำนี้ ดูstackoverflow.com/a/38341921/1441122
Stuart Marks

คำตอบ:


85

อะไรคือความแตกต่างระหว่างพวกเขา ...

"Fail-safe" ( ในทางวิศวกรรม ) หมายถึงสิ่งที่ล้มเหลวในลักษณะที่ไม่ก่อให้เกิดความเสียหายน้อยที่สุด พูดอย่างเคร่งครัดไม่มีสิ่งดังกล่าวใน Java เป็นตัววนซ้ำที่ไม่ปลอดภัย หากตัววนซ้ำล้มเหลว (ในความหมายปกติของ "ล้มเหลว") คุณสามารถคาดหวังความเสียหายที่จะเกิดขึ้นได้

ฉันสงสัยว่าคุณหมายถึงตัวทำซ้ำที่ "สม่ำเสมอเพียงเล็กน้อย" Javadoc พูดว่า:

"การใช้งานคอลเลคชันพร้อมกันส่วนใหญ่ (รวมถึงคิวส่วนใหญ่) ยังแตกต่างจากอนุสัญญา java.util ตามปกติตรงที่ Iterators และ Spliterators ให้ความสอดคล้องกันเล็กน้อยมากกว่าการส่งผ่านที่ล้มเหลวอย่างรวดเร็ว"

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

"Fail-fast" ( ในการออกแบบระบบ ) หมายความว่าเงื่อนไขความล้มเหลวจะได้รับการตรวจสอบอย่างเข้มงวดเพื่อให้ตรวจพบเงื่อนไขความล้มเหลว (หากเป็นไปได้1 ) ก่อนที่จะเกิดความเสียหายมากเกินไป ใน Java ตัววนซ้ำแบบเร็วที่ล้มเหลวจะล้มเหลวโดยการโยนไฟล์ConcurrentModificationException.

อีกทางเลือกหนึ่งสำหรับ "ล้มเหลว - เร็ว" และ "ไม่สอดคล้องกัน" คือความหมายที่การวนซ้ำล้มเหลวโดยไม่สามารถคาดเดาได้ เช่นบางครั้งให้คำตอบผิดหรือโยนข้อยกเว้นที่ไม่คาดคิด (นี่คือลักษณะการทำงานของการใช้งานมาตรฐานบางอย่างของEnumerationAPI ใน Java เวอร์ชันแรก ๆ )

... และแตกต่างจากตัววนซ้ำที่เราใช้ในการรวบรวมหรือไม่

ไม่ใช่คุณสมบัติเหล่านี้เป็นคุณสมบัติของตัวทำซ้ำที่ใช้โดยประเภทคอลเล็กชันมาตรฐาน คือพวกเขามีทั้ง "ล้มเหลวอย่างรวดเร็ว" หรือ "ที่สอดคล้องกันนิดหน่อย" ... เมื่อใช้อย่างถูกต้องเกี่ยวกับการประสานและหน่วยความจำแบบ Java 1


โดยทั่วไปแล้วตัวทำซ้ำแบบเร็วที่ล้มเหลวจะถูกนำไปใช้โดยใช้ตัวvolatileนับบนวัตถุคอลเลกชัน

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

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


1 - ไรเดอร์คือพฤติกรรมที่ล้มเหลวอย่างรวดเร็วถือว่า ID แอปพลิเคชันถูกต้องตามการซิงโครไนซ์และโมเดลหน่วยความจำ นั่นหมายความว่า (ตัวอย่างเช่น) หากคุณทำซ้ำArrayListโดยไม่มีการซิงโครไนซ์ที่เหมาะสมผลลัพธ์อาจเป็นผลลัพธ์ของรายการที่เสียหาย กลไก "ล้มเหลวอย่างรวดเร็ว" อาจตรวจพบการแก้ไขพร้อมกัน (แม้ว่าจะไม่ได้รับการรับรอง) แต่จะไม่ตรวจพบการทุจริตที่อยู่ภายใต้ ตัวอย่างเช่นjavadocสำหรับVector.iterator()กล่าวว่า:

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


42

เป็นประเภทที่ค่อนข้างล้มเหลวเร็วและไม่สอดคล้องกัน:

ตัวทำซ้ำจากjava.utilแพ็กเกจโยนConcurrentModificationExceptionหากคอลเลกชันถูกแก้ไขโดยวิธีการของคอลเลกชัน (เพิ่ม / ลบ) ในขณะที่ทำซ้ำ

java.util.concurrentโดยทั่วไปแล้วตัววนซ้ำจากแพ็กเกจจะวนซ้ำบนสแน็ปช็อตและอนุญาตให้มีการแก้ไขพร้อมกัน แต่อาจไม่สะท้อนถึงการอัปเดตคอลเล็กชันหลังจากสร้างตัววนซ้ำแล้ว


Iterator เป็นตัวอย่างของความล้มเหลวอย่างรวดเร็วในขณะที่การแจงนับไม่ปลอดภัย
Ajay Sharma

5
@AjaySharma - ไม่ถูกต้องในการนับสองครั้ง 1) ไม่ระบุIteratorหรือEnumerationระบุลักษณะการทำงานว่าล้มเหลวอย่างรวดเร็วหรือไม่ปลอดภัย เป็นการใช้งานเฉพาะ (เช่นวิธีการรวบรวมiterator()/ elements()etc เฉพาะที่ส่งคืนวัตถุเหล่านี้) ที่ระบุลักษณะการทำงาน 2) การใช้งานการแจงนับทั่วไปจะไม่ล้มเหลวได้อย่างรวดเร็วหรือไม่ปลอดภัย
Stephen C

22

ข้อแตกต่างเพียงอย่างเดียวคือตัวทำซ้ำที่ไม่ปลอดภัยไม่ได้โยนข้อยกเว้นใด ๆ ตรงกันข้ามกับ Iterator ที่ล้มเหลวอย่างรวดเร็ว

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

Iterator ของ CopyOnWriteArrayList เป็นตัวอย่างของ Iterator ที่ไม่ปลอดภัยและตัววนซ้ำที่เขียนโดย ConcurrentHashMap keySet ยังเป็นตัววนซ้ำที่ไม่ปลอดภัยและอย่าโยน ConcurrentModificationException ใน Java


ฉันไม่เห็นตัวทำซ้ำ ConcurrentHashMap กำลังทำงานบนโคลน () .. :( บางครั้งมันจะแสดงการอัปเดตบางอย่างในขณะที่ทำซ้ำ ..
Kanagavelu Sugumar

0

สถานการณ์นี้เกี่ยวข้องกับ "การประมวลผลพร้อมกัน" หมายความว่ามีผู้ใช้มากกว่าหนึ่งรายที่เข้าถึงทรัพยากรเดียวกัน ในสถานการณ์เช่นนี้ผู้ใช้รายหนึ่งพยายามแก้ไขทรัพยากรนั้นซึ่งทำให้เกิด 'ConcurrentProcessingException' เนื่องจากในกรณีนั้นผู้ใช้รายอื่นได้รับข้อมูลที่ไม่เหมาะสม ทั้งสองประเภทนี้เกี่ยวข้องกับสถานการณ์แบบนี้

พูดง่ายๆว่า

ล้มเหลวอย่างรวดเร็ว:

  • Iterators โยน ConcurrentModificationException ทันทีหากเกิดการปรับเปลี่ยนโครงสร้าง (เพิ่มอัปเดตลบ)
  • ตัวอย่าง: ArrayList, HashMap, TreeSet

ล้มเหลวในความปลอดภัย :

  • ที่นี่ Iterators ไม่ทิ้งข้อยกเว้นใด ๆ เนื่องจากทำงานบนโคลนของคอลเล็กชันไม่ใช่ของดั้งเดิม ดังนั้นพวกเขาจึงเป็นผู้ทำซ้ำที่ไม่ปลอดภัย
  • ตัวอย่าง: CopyOnWriteArrayList, ConcurrentHashMap
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.