หากฉันมีเธรดหลายเธรดที่เข้าถึง HashMap แต่รับประกันได้ว่าพวกเขาจะไม่เข้าถึงคีย์เดียวกันในเวลาเดียวกันนั่นอาจทำให้เกิดสภาวะการแข่งขันได้หรือไม่
หากฉันมีเธรดหลายเธรดที่เข้าถึง HashMap แต่รับประกันได้ว่าพวกเขาจะไม่เข้าถึงคีย์เดียวกันในเวลาเดียวกันนั่นอาจทำให้เกิดสภาวะการแข่งขันได้หรือไม่
คำตอบ:
คำตอบของ In @ dotsid เขาบอกว่า:
หากคุณเปลี่ยน HashMap ด้วยวิธีใดก็ตามโค้ดของคุณจะเสีย
เขาถูกต้อง HashMap ที่อัปเดตโดยไม่มีการซิงโครไนซ์จะหยุดทำงานแม้ว่าเธรดกำลังใช้ชุดคีย์ที่ไม่ต่อกัน นี่คือบางส่วนของสิ่งที่อาจผิดพลาด
หากเธรดหนึ่งเธรดหนึ่งเธรดputอื่นอาจเห็นค่าเก่าสำหรับขนาดของแฮชแมป
เมื่อเธรดputทำการสร้างตารางขึ้นมาใหม่เธรดอื่นอาจเห็นการอ้างอิงอาร์เรย์แฮชแท็กเวอร์ชันชั่วคราวหรือเก่าขนาดเนื้อหาหรือแฮชเชน ความโกลาหลอาจตามมา
เมื่อเธรดทำputคีย์ที่ชนกับคีย์ที่ใช้โดยเธรดอื่นและเธรดหลังทำputคีย์ของเธรดหลังอาจเห็นสำเนาเก่าของการอ้างอิงแฮชเชน ความโกลาหลอาจตามมา
เมื่อเธรดหนึ่งตรวจสอบตารางด้วยคีย์ที่ชนกับคีย์ของเธรดอื่น ๆ บางคีย์อาจพบคีย์นั้นบนโซ่ มันจะเรียกเท่ากับบนคีย์นั้นและหากเธรดไม่ซิงโครไนซ์เมธอด equals อาจพบสถานะเก่าในคีย์นั้น
และหากคุณมีสองเธรดที่ทำพร้อมกันputหรือremoveร้องขอก็มีโอกาสมากมายสำหรับเงื่อนไขการแข่งขัน
ฉันคิดได้สามวิธี:
ConcurrentHashMap.HashMapแต่ซิงโครไนซ์กับภายนอก เช่นการใช้ mutexes ดั้งเดิมLockวัตถุ ฯลฯHashMapสำหรับแต่ละเธรด หากเธรดมีชุดคีย์ที่ไม่ปะติดปะต่อกันจริงๆก็ไม่จำเป็นต้องมี (จากมุมมองของอัลกอริทึม) เพื่อให้พวกเขาแชร์แผนที่เดียว อันที่จริงหากอัลกอริทึมของคุณเกี่ยวข้องกับเธรดที่วนซ้ำคีย์ค่าหรือรายการของแผนที่ในบางจุดการแยกแผนที่เดียวออกเป็นหลายแผนที่อาจทำให้เกิดการเร่งความเร็วอย่างมากสำหรับส่วนนั้นของการประมวลผลเพียงใช้ ConcurrentHashMap ConcurrentHashMap ใช้การล็อกหลายรายการซึ่งครอบคลุมช่วงของที่เก็บข้อมูลแฮชเพื่อลดโอกาสในการโต้แย้งการล็อก มีผลกระทบต่อประสิทธิภาพเล็กน้อยในการได้มาซึ่งการล็อกที่ไม่มีใครโต้แย้ง
เพื่อตอบคำถามเดิมของคุณ: ตามที่ javadoc ตราบใดที่โครงสร้างของแผนที่ไม่เปลี่ยนแปลงคุณก็สบายดี ซึ่งหมายความว่าไม่มีการลบองค์ประกอบใด ๆ เลยและไม่มีการเพิ่มคีย์ใหม่ที่ไม่มีอยู่ในแผนที่ การแทนที่ค่าที่เกี่ยวข้องกับคีย์ที่มีอยู่นั้นทำได้ดี
หากเธรดหลายเธรดเข้าถึงแฮชแม็พพร้อมกันและเธรดอย่างน้อยหนึ่งเธรดแก้ไขแม็พเชิงโครงสร้างเธรดนั้นจะต้องซิงโครไนซ์ภายนอก (การปรับเปลี่ยนโครงสร้างคือการดำเนินการใด ๆ ที่เพิ่มหรือลบการแมปอย่างน้อยหนึ่งรายการการเปลี่ยนค่าที่เชื่อมโยงกับคีย์ที่อินสแตนซ์มีอยู่แล้วเท่านั้นไม่ใช่การแก้ไขโครงสร้าง)
แม้ว่าจะไม่มีการรับประกันเกี่ยวกับการมองเห็น ดังนั้นคุณต้องเต็มใจที่จะยอมรับการดึงข้อมูลการเชื่อมโยงเก่า ๆ เป็นครั้งคราว
ขึ้นอยู่กับความหมายของคุณภายใต้ "การเข้าถึง" หากคุณเพิ่งอ่านคุณสามารถอ่านได้แม้กระทั่งคีย์เดียวกันตราบใดที่การเปิดเผยข้อมูลรับรองภายใต้กฎ" เกิดขึ้นก่อน " ซึ่งหมายความว่าHashMapไม่ควรเปลี่ยนและการเปลี่ยนแปลงทั้งหมด (การก่อสร้างเริ่มต้น) ควรจะเสร็จสิ้นก่อนที่จะอ่านใด ๆ HashMapเริ่มต้นที่จะเข้าถึง
หากคุณเปลี่ยนHashMapวิธีใด ๆ แสดงว่ารหัสของคุณเสีย @Stephen C ให้คำอธิบายที่ดีมากว่าทำไม
แก้ไข: หากกรณีแรกเป็นสถานการณ์จริงของคุณฉันขอแนะนำให้คุณใช้Collections.unmodifiableMap()เพื่อให้แน่ใจว่า HashMap ของคุณจะไม่มีการเปลี่ยนแปลง วัตถุที่ชี้โดยHashMapไม่ควรเปลี่ยนแปลงเช่นกันดังนั้นการใช้finalคำหลักเชิงรุกสามารถช่วยคุณได้
และอย่างที่ @Lars Andren กล่าวว่าConcurrentHashMapเป็นทางเลือกที่ดีที่สุดในกรณีส่วนใหญ่
unmodifiableMapทำให้แน่ใจว่าลูกค้าไม่สามารถเปลี่ยนแผนที่ได้ ไม่ดำเนินการใด ๆ เพื่อให้แน่ใจว่าจะไม่มีการเปลี่ยนแปลงแผนที่ต้นแบบ
                    การแก้ไข HashMap โดยไม่มีการซิงโครไนซ์อย่างเหมาะสมจากสองเธรดอาจทำให้เกิดสภาวะการแย่งชิงได้ง่าย
put()นำไปสู่การปรับขนาดของตารางภายในการดำเนินการนี้จะใช้เวลาสักครู่และเธรดอื่นจะยังคงเขียนลงในตารางเก่าput()สำหรับคีย์ที่แตกต่างกันจะนำไปสู่การอัปเดตที่เก็บข้อมูลเดียวกันหากรหัสแฮชของคีย์มีขนาดเท่ากันสำหรับตาราง (อันที่จริงความสัมพันธ์ระหว่าง hashcode และ bucket index นั้นซับซ้อนกว่า แต่ก็อาจเกิดการชนกันได้)HashMapการนำไปใช้งานที่คุณใช้คุณอาจได้รับความเสียหายของHashMapโครงสร้างข้อมูลเป็นต้นสาเหตุจากความผิดปกติของหน่วยความจำ