ConcurrentHashMap และ Collections.synchronizedMap (แผนที่) แตกต่างกันอย่างไร


607

ฉันมีแผนที่ซึ่งจะต้องแก้ไขหลายกระทู้พร้อมกัน

ดูเหมือนจะมีการใช้งานแผนที่ที่แตกต่างกันสามแบบใน Java API:

  • Hashtable
  • Collections.synchronizedMap(Map)
  • ConcurrentHashMap

จากสิ่งที่ฉันเข้าใจHashtableคือการใช้งานเก่า (การขยายDictionaryคลาสล้าสมัย) ซึ่งได้รับการดัดแปลงในภายหลังเพื่อให้พอดีกับMapอินเตอร์เฟส แม้ว่าจะมีการซิงโครไนซ์ แต่ดูเหมือนว่าจะมีปัญหาเรื่องความสามารถในการปรับขนาดได้และไม่สนับสนุนโครงการใหม่ ๆ

แต่แล้วอีกสองอันล่ะ? อะไรคือความแตกต่างระหว่าง Maps ที่ส่งคืนโดยCollections.synchronizedMap(Map)และConcurrentHashMaps? สิ่งที่เหมาะกับสถานการณ์ใด


7
@SmilesinaJar Link เสียแล้วนี่เป็นสำเนาเก็บถาวรของบทความนี้: ทำไม ConcurrentHashMap ดีกว่า Hashtable และดีเท่า HashMap
informatik01

2
IBM: วิธี ConcurrentHashMap เสนอการทำงานพร้อมกันที่สูงขึ้นโดยไม่ลด
ทอน

FYI, Java 6 นำมาConcurrentSkipListMapซึ่งMapการใช้งานแบบปลอดภัยต่อเธรด ออกแบบมาให้พร้อมกันอย่างมากภายใต้โหลดโดยใช้อัลกอริทึมข้ามรายการ
Basil Bourque

คำตอบ:


423

ConcurrentHashMapสำหรับความต้องการของการใช้งาน อนุญาตให้แก้ไขแผนที่พร้อมกันจากหลาย ๆ กระทู้โดยไม่จำเป็นต้องปิดกั้น Collections.synchronizedMap(map)สร้างแผนที่การปิดกั้นซึ่งจะลดประสิทธิภาพแม้ว่าจะมั่นใจได้ว่ามีความสอดคล้อง (ถ้าใช้อย่างเหมาะสม)

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


8
มองไปที่ซอร์สโค้ดแผนที่ตรงกันเป็นเพียงการดำเนินการกับหนึ่ง mutex (ปิดกั้น) ในขณะที่ ConcurrentHashMap มีความซับซ้อนมากขึ้นในการจัดการกับการเข้าถึงพร้อมกัน
Vinze

123
โปรดทราบว่า ConcurrentHashMap ไม่อนุญาตให้ใช้คีย์หรือค่าว่าง ดังนั้นจึงไม่ใช่ทางเลือกที่เท่าเทียมกันของแผนที่ที่มีการซิงโครไนซ์
onejigtwojig

24
ฉันคิดว่าคุณควรอ่านhttp://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/
Mr Spark

5
@AbdullahShaikh ปัญหาที่เกิดขึ้นในบทความนั้นได้รับการแก้ไขใน Java 7 และมีการปรับปรุงเพิ่มเติมใน Java 8
pulse0ne

5
@hengxin: ทันทีที่คุณกำลังดำเนินการประกอบด้วยหลายแบบสอบถามหรืออัปเดตแผนที่หรือเมื่อคุณวนซ้ำบนแผนที่คุณต้องซิงโครไนซ์แผนที่ด้วยตนเองเพื่อให้แน่ใจว่ามีความสอดคล้องกัน การซิงโครไนซ์แผนที่รับประกันความสอดคล้องสำหรับการดำเนินงานเดียวเท่านั้น (การเรียกใช้เมธอด) บนแผนที่ซึ่งทำให้มันไร้ค่ามากกว่าบ่อยครั้งเนื่องจากการดำเนินการในชีวิตจริงส่วนใหญ่นั้นไม่ไร้สาระดังนั้นคุณจึงต้องซิงโครไนซ์ด้วยตนเอง
Holger

241
╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║   Property    ║     HashMap       ║    Hashtable      ║  ConcurrentHashMap  ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║      Null     ║     allowed       ║              not allowed                ║
║  values/keys  ║                   ║                                         ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║ Thread-safety ║                   ║                                         ║
║   features    ║       no          ║                  yes                    ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║     Lock      ║       not         ║ locks the whole   ║ locks the portion   ║        
║  mechanism    ║    applicable     ║       map         ║                     ║ 
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║   Iterator    ║               fail-fast               ║ weakly consistent   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

เกี่ยวกับกลไกการล็อค: Hashtable ล็อควัตถุในขณะที่ConcurrentHashMapล็อคที่ฝากข้อมูลเท่านั้น


13
Hashtableไม่ได้ล็อคส่วนของแผนที่ ดูการใช้งาน มันใช้synchronizedกุญแจโดยไม่มีการล็อคดังนั้นมันจึงหมายความว่ามันล็อคทั้งhashtableการใช้งานแต่ละครั้ง
RMachnik

6
สิ่งที่เกี่ยวกับ synchronMap?
ซามูเอลเอ็ดวินวอร์ด

3
Collections.syncronizedMap พฤติกรรมเป็นแผนที่สำรองยกเว้นวิธีการทั้งหมดที่มีความปลอดภัยเธรด
Sergii Shevchyk

5
ฉันจะพิมพ์ตารางและขายในราคา $ 5 ต่อคน;) Good one @shevchyk
realPK

แก้ไข: ไม่มีทั้งเธรดที่ปลอดภัย นั่นเป็นความเข้าใจผิดเล็กน้อยสำหรับนักพัฒนาใหม่ โปรดดูที่: ibm.com/developerworks/java/library/j-jtp07233/index.htmlเพื่อให้เข้าใจว่าแม้ ConcurrentHashMap จะไม่ปลอดภัยสำหรับเธรดจากการแข่งขันข้อมูลภายนอก (เช่น: 1 เธรดลบค่าและลองอีกครั้งในภายหลังตรวจสอบว่ามีอยู่หรือไม่และใส่ไว้หากไม่ใช่นั่นคือ data race condition และยังหมายความว่าแม้จะใช้ "ConcurrentHashMap" คุณจะไม่บรรเทาปัญหาความปลอดภัยของเธรดทั้งหมด
Zombies

142

"ปัญหาเกี่ยวกับความสามารถในการปรับขยาย" สำหรับHashtableมีอยู่ในลักษณะเดียวกันCollections.synchronizedMap(Map)- พวกเขาใช้การซิงโครไนซ์อย่างง่ายมากซึ่งหมายความว่ามีเพียงเธรดเดียวเท่านั้นที่สามารถเข้าถึงแผนที่ในเวลาเดียวกัน

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

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


4
นั่นคือสิ่งที่ฉันต้องการ! :) Iterator ที่ไม่มีการซิงโครไนซ์เป็นเพียงความหวานที่บริสุทธิ์เพียงอย่างเดียว! ขอบคุณสำหรับข้อมูล! :) (:
Kounavi

คำตอบที่ดี .. แต่หมายความว่าในระหว่างการดึงข้อมูลเธรดจะไม่ได้รับการอัปเดตล่าสุดเนื่องจากเธรดผู้อ่านไม่ซิงค์กัน
MrA

@MrA: คุณถามเกี่ยวกับ ConcurrentHashMap หรือไม่? และคุณหมายถึงอะไรโดย "การดึง"
Michael Borgwardt

4
@Michael Borgwardt สำหรับ ConcurrentHashmap สำหรับเช่น สมมติว่ามีหลายกระทู้ บางคนกำลังอัปเดตแผนที่และบางคนกำลังรับข้อมูลจากแผนที่เดียวกัน ดังนั้นในสถานการณ์นี้เมื่อเธรดพยายามอ่านมันรับประกันว่าพวกเขาจะได้รับข้อมูลล่าสุดที่ได้รับการปรับปรุงเนื่องจากเธรดผู้อ่านไม่จำเป็นต้องล็อคไว้
MrA

35

ConcurrentHashMap เป็นที่ต้องการเมื่อคุณสามารถใช้ได้แม้ว่าจะต้องการ Java 5 เป็นอย่างน้อย

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

ฉันพบรายการบล็อกที่สร้างตารางจากหนังสือยอดนิยมJava Concurrency In Practiceซึ่งฉันแนะนำอย่างละเอียด

Collections.synchronizedMap เหมาะสมจริง ๆ ก็ต่อเมื่อคุณต้องการสรุปแผนที่ด้วยคุณสมบัติอื่น ๆ อาจเป็นแผนที่ที่เรียงลำดับเช่น TreeMap


2
ใช่ - ดูเหมือนว่าฉันพูดถึงหนังสือเล่มนั้นในคำตอบอื่น ๆ ที่ฉันทำ!
Bill Michell

@BillMichell ลิงก์เสีย

@Govinda ปิด javascript ก่อนเข้าใช้ลิงค์ รายการบล็อกยังคงอยู่ที่นั่น!
Bill Michell

32

ความแตกต่างที่สำคัญระหว่างสองสิ่งนี้คือการConcurrentHashMapล็อกเฉพาะส่วนของข้อมูลที่ถูกอัพเดตในขณะที่เธรดอื่นสามารถเข้าถึงได้โดยเธรดอื่น อย่างไรก็ตามCollections.synchronizedMap()จะล็อกข้อมูลทั้งหมดในขณะที่อัพเดตเธรดอื่นสามารถเข้าถึงข้อมูลได้เมื่อปลดล็อกเท่านั้น ConcurrentHashMapหากมีการปรับปรุงการดำเนินงานจำนวนมากและจำนวนเงินขนาดเล็กญาติของการดำเนินงานอ่านที่คุณควรเลือก

อีกหนึ่งความแตกต่างอื่น ๆ คือConcurrentHashMapจะไม่รักษาลำดับขององค์ประกอบในแผนที่ผ่านมันคล้ายกับHashMapเมื่อเก็บข้อมูล ไม่มีการรับประกันว่ารักษาลำดับองค์ประกอบ ในขณะที่Collections.synchronizedMap()จะรักษาลำดับองค์ประกอบของแผนที่ผ่านมาตัวอย่างเช่นถ้าคุณส่งTreeMapไปยังConcurrentHashMapลำดับองค์ประกอบในConcurrentHashMapอาจไม่เหมือนกับคำสั่งในTreeMapแต่Collections.synchronizedMap()จะรักษาลำดับ

นอกจากนี้ConcurrentHashMapสามารถรับประกันได้ว่าไม่มีการConcurrentModificationExceptionโยนขณะที่เธรดหนึ่งกำลังอัพเดตแผนที่และเธรดอื่นกำลังข้ามตัววนซ้ำที่ได้รับจากแผนที่ อย่างไรก็ตามCollections.synchronizedMap()ไม่รับประกันในเรื่องนี้

มีการโพสต์ConcurrentSkipListMapซึ่งแสดงให้เห็นถึงความแตกต่างของทั้งสองและที่


13

ทำข้อมูลแผนที่ให้ตรงกัน:

แผนที่ที่ซิงโครไนซ์ก็ไม่แตกต่างจาก Hashtable มากนักและให้ประสิทธิภาพที่คล้ายกันในโปรแกรม Java พร้อมกัน ความแตกต่างเพียงอย่างเดียวระหว่าง Hashtable และ SynchronizedMap นั้นคือ SynchronizedMap ไม่ใช่มรดกและคุณสามารถล้อมแผนที่ใด ๆ เพื่อสร้างเวอร์ชันที่ถูกซิงโครไนซ์โดยใช้วิธีการ Collections.synchronizedMap ()

ConcurrentHashMap:

คลาส ConcurrentHashMap จัดเตรียมรุ่นมาตรฐานพร้อมกันของ HashMap นี่คือการปรับปรุงฟังก์ชั่น synchronMap ที่มีให้ในคลาส Collections

ต่างจากแผนที่ Hashtable และซิงโครไนซ์มันจะไม่ล็อคแผนที่ทั้งหมด แต่จะแบ่งแผนที่เป็นส่วน ๆ และทำการล็อกบนแผนที่เหล่านั้น มันจะทำงานได้ดีขึ้นถ้าจำนวนเธรดผู้อ่านมากกว่าจำนวนเธรดผู้เขียน

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

ConcurrentHashMap ไม่ได้โยน ConcurrentModificationException

ConcurrentHashMap ไม่ได้โยน ConcurrentModificationException หากเธรดหนึ่งพยายามแก้ไขในขณะที่เธรดอื่นวนซ้ำ

ความแตกต่างระหว่าง synchornizedMap และ ConcurrentHashMap

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

ConcurrentHashMap ไม่อนุญาตให้ใช้ปุ่ม null หรือค่า Null ในขณะที่ HashMap ที่ซิงโครไนซ์จะอนุญาตให้ใช้หนึ่งคีย์ได้

ลิงค์ที่คล้ายกัน

link1

link2

การเปรียบเทียบประสิทธิภาพ


12
  • HashtableและConcurrentHashMapไม่อนุญาตให้ใช้nullคีย์หรือnullค่า

  • Collections.synchronizedMap(Map)ประสานทุกการดำเนินงาน ( get, put, sizeฯลฯ )

  • ConcurrentHashMap รองรับการทำงานพร้อมกันอย่างเต็มรูปแบบของการดึงข้อมูลและปรับการทำงานพร้อมกันที่คาดไว้สำหรับการปรับปรุง

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


12

ในConcurrentHashMapการล็อคถูกนำไปใช้กับกลุ่มแทนที่จะเป็นแผนที่ทั้งหมด แต่ละเซกเมนต์จัดการตารางแฮชภายในของตนเอง การล็อคถูกนำไปใช้สำหรับการดำเนินการอัพเดทเท่านั้น Collections.synchronizedMap(Map)ประสานแผนที่ทั้งหมด



9

คุณถูกต้องHashTableคุณสามารถลืมมันได้

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

synchronized (records) {
  Record rec = records.get(id);
  if (rec == null) {
      rec = new Record(id);
      records.put(id, rec);
  }
  return rec;
}

อย่างไรก็ตามอย่าคิดว่าConcurrentHashMapเป็นทางเลือกที่ง่ายสำหรับบล็อกHashMapแบบทั่วไปsynchronizedตามที่แสดงด้านบน อ่านนี้บทความที่จะเข้าใจความซับซ้อนที่ดีกว่า


7

ที่นี่มีไม่กี่:

1) ConcurrentHashMap ล็อคเฉพาะส่วนของ Map เท่านั้น แต่ SynchronizedMap ล็อค MAp ทั้งหมด
2) ConcurrentHashMap มีประสิทธิภาพที่ดีขึ้นกว่า SynchronizedMap และปรับขนาดได้มากขึ้น
3) ในกรณีที่ผู้อ่านหลายคนและนักเขียนโสด ConcurrentHashMap เป็นตัวเลือกที่ดีที่สุด

ข้อความนี้มาจากความแตกต่างระหว่าง ConcurrentHashMap และ hashtable ใน Java


7

เราสามารถบรรลุความปลอดภัยของเธรดโดยใช้ ConcurrentHashMap และ synchronisedHashmap และ Hashtable แต่มีความแตกต่างมากถ้าคุณดูสถาปัตยกรรมของพวกเขา

  1. synchronisedHashmap และ Hashtable

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

  1. ConcurrentHashMap

มันจะรักษาล็อคในระดับเซกเมนต์ มันมี 16 ส่วนและรักษาระดับการทำงานพร้อมกันเป็น 16 โดยค่าเริ่มต้น ดังนั้นในแต่ละครั้งสามารถมี 16 เธรดที่สามารถทำงานบน ConcurrentHashMap ได้ นอกจากนี้การดำเนินการอ่านไม่จำเป็นต้องล็อค ดังนั้นจำนวนเธรดใด ๆ ที่สามารถทำการดำเนินการ get ได้

หาก thread1 ต้องการดำเนินการวางในส่วนที่ 2 และ thread2 ต้องการที่จะดำเนินการใส่ในส่วนที่ 4 แล้วมันได้รับอนุญาตที่นี่ หมายความว่า 16 เธรดสามารถทำการอัปเดต (วาง / ลบ) บน ConcurrentHashMap ได้ตลอดเวลา

ดังนั้นเวลาที่รอจะน้อยกว่าที่นี่ ดังนั้นประสิทธิภาพค่อนข้างดีกว่า synchronizedHashmap และ Hashtable


1
1 จะเกิดอะไรขึ้นถ้าหลายเธรดพยายามแก้ไขบล็อกเดียวกัน 2. จะเกิดอะไรขึ้นถ้าพูดว่าสองเธรดพยายามอ่านข้อมูลจากบล็อกเดียวกันที่มีเธรดอื่นถ้าเขียนข้อมูลในเวลาเดียวกัน
prnjn

6

ConcurrentHashMap

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

SynchronizedHashMap

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

แหล่ง


4

ConcurrentHashMap ถูกปรับให้เหมาะสมสำหรับการเข้าถึงพร้อมกัน

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


4

มีคุณลักษณะที่สำคัญอย่างหนึ่งที่ควรทราบเกี่ยวกับConcurrentHashMapนอกเหนือจากคุณสมบัติที่เกิดขึ้นพร้อมกันซึ่งเป็นตัววนซ้ำที่ไม่ปลอดภัย ฉันได้เห็นนักพัฒนาใช้ConcurrentHashMapเพียงเพราะพวกเขาต้องการที่จะแก้ไขชุด - ใส่ / ลบในขณะที่ซ้ำมัน Collections.synchronizedMap(Map)ไม่ได้ให้ตัววนซ้ำที่ไม่ปลอดภัยแต่ให้ตัววนซ้ำที่ไม่ได้ใช้เร็วแทน ตัววนซ้ำอย่างรวดเร็วใช้สแน็ปช็อตขนาดของแผนที่ซึ่งไม่สามารถแก้ไขได้ในระหว่างการทำซ้ำ


3
  1. หากความสอดคล้องของข้อมูลมีความสำคัญอย่างยิ่งให้ใช้ Hashtable หรือ Collections.synchronizedMap (แผนที่)
  2. หากความเร็ว / ประสิทธิภาพเป็นสิ่งสำคัญอย่างยิ่งและการอัปเดตข้อมูลสามารถถูกละเมิดได้ - ใช้ ConcurrentHashMap

2

โดยทั่วไปถ้าคุณต้องการใช้ConcurrentHashMapให้แน่ใจว่าคุณพร้อมที่จะพลาด 'อัพเดท'
(เช่นเนื้อหาการพิมพ์ของ HashMap ไม่แน่ใจว่ามันจะพิมพ์แผนที่ที่ทันสมัย) และใช้ API CyclicBarrierเพื่อให้แน่ใจว่าโปรแกรมของคุณมีความสอดคล้องกัน วงจรชีวิต.


1

Collections.synchronizedMap () วิธีการประสานวิธีการทั้งหมดของ HashMap และลดมันได้อย่างมีประสิทธิภาพโครงสร้างข้อมูลที่หนึ่งกระทู้สามารถป้อนได้ตลอดเวลาเพราะมันล็อคทุกวิธีในการล็อคทั่วไป

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


1

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

วิธีการใช้งาน ConcurrentHashMap

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

หากคุณมีความสนใจในคุณสมบัติที่สำคัญบางอย่างของ ConcurrentHashMap และเมื่อคุณควรใช้การรับรู้ของ Map นี้ - ฉันแค่ใส่ลิงค์ไปยังบทความที่ดี - วิธีใช้ ConcurrentHashMap ใน Java


0

นอกจากสิ่งที่ได้รับการแนะนำฉันต้องการโพสต์ซอร์สโค้ดที่เกี่ยวข้องกับ SynchronizedMapฉันต้องการที่จะโพสต์รหัสที่มาเกี่ยวข้องกับ

เพื่อให้Mapด้ายปลอดภัยเราสามารถใช้Collections.synchronizedMapคำสั่งและป้อนอินสแตนซ์แผนที่เป็นพารามิเตอร์

การใช้งานของsynchronizedMapในCollectionsเป็นเหมือนด้านล่าง

   public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
        return new SynchronizedMap<>(m);
    }

อย่างที่คุณเห็นMapวัตถุอินพุตถูกห่อหุ้มด้วยSynchronizedMapวัตถุ
มาขุดลงไปปฏิบัติSynchronizedMapกัน

 private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;

        private final Map<K,V> m;     // Backing Map
        final Object      mutex;        // Object on which to synchronize

        SynchronizedMap(Map<K,V> m) {
            this.m = Objects.requireNonNull(m);
            mutex = this;
        }

        SynchronizedMap(Map<K,V> m, Object mutex) {
            this.m = m;
            this.mutex = mutex;
        }

        public int size() {
            synchronized (mutex) {return m.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return m.isEmpty();}
        }
        public boolean containsKey(Object key) {
            synchronized (mutex) {return m.containsKey(key);}
        }
        public boolean containsValue(Object value) {
            synchronized (mutex) {return m.containsValue(value);}
        }
        public V get(Object key) {
            synchronized (mutex) {return m.get(key);}
        }

        public V put(K key, V value) {
            synchronized (mutex) {return m.put(key, value);}
        }
        public V remove(Object key) {
            synchronized (mutex) {return m.remove(key);}
        }
        public void putAll(Map<? extends K, ? extends V> map) {
            synchronized (mutex) {m.putAll(map);}
        }
        public void clear() {
            synchronized (mutex) {m.clear();}
        }

        private transient Set<K> keySet;
        private transient Set<Map.Entry<K,V>> entrySet;
        private transient Collection<V> values;

        public Set<K> keySet() {
            synchronized (mutex) {
                if (keySet==null)
                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
                return keySet;
            }
        }

        public Set<Map.Entry<K,V>> entrySet() {
            synchronized (mutex) {
                if (entrySet==null)
                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
                return entrySet;
            }
        }

        public Collection<V> values() {
            synchronized (mutex) {
                if (values==null)
                    values = new SynchronizedCollection<>(m.values(), mutex);
                return values;
            }
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return m.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return m.hashCode();}
        }
        public String toString() {
            synchronized (mutex) {return m.toString();}
        }

        // Override default methods in Map
        @Override
        public V getOrDefault(Object k, V defaultValue) {
            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
        }
        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            synchronized (mutex) {m.forEach(action);}
        }
        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            synchronized (mutex) {m.replaceAll(function);}
        }
        @Override
        public V putIfAbsent(K key, V value) {
            synchronized (mutex) {return m.putIfAbsent(key, value);}
        }
        @Override
        public boolean remove(Object key, Object value) {
            synchronized (mutex) {return m.remove(key, value);}
        }
        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
        }
        @Override
        public V replace(K key, V value) {
            synchronized (mutex) {return m.replace(key, value);}
        }
        @Override
        public V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
        }
        @Override
        public V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
        }
        @Override
        public V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.compute(key, remappingFunction);}
        }
        @Override
        public V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
        }

        private void writeObject(ObjectOutputStream s) throws IOException {
            synchronized (mutex) {s.defaultWriteObject();}
        }
    }

สิ่งที่SynchronizedMapสามารถสรุปได้ว่าเป็นการเพิ่มการล็อคเดียวกับวิธีการหลักของMapวัตถุอินพุต ทุกวิธีที่ป้องกันโดยล็อคไม่สามารถเข้าถึงได้โดยหลายกระทู้ในเวลาเดียวกัน นั่นหมายถึงการดำเนินงานปกติเช่นputและgetสามารถดำเนินการโดยเธรดเดียวในเวลาเดียวกันสำหรับข้อมูลทั้งหมดในMapวัตถุ

ทำให้Mapเธรดวัตถุปลอดภัยในขณะนี้ แต่ประสิทธิภาพอาจเป็นปัญหาในบางสถานการณ์

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.