Sự khác biệt giữa ConcảnHashMap và Collections.syn syncizedMap (Bản đồ) là gì?


607

Tôi có một Bản đồ được sửa đổi đồng thời bởi một số chủ đề.

Dường như có ba triển khai Bản đồ được đồng bộ hóa khác nhau trong API Java:

  • Hashtable
  • Collections.synchronizedMap(Map)
  • ConcurrentHashMap

Theo những gì tôi hiểu, Hashtablelà một triển khai cũ (mở rộng Dictionarylớp lỗi thời ), đã được điều chỉnh sau này để phù hợp với Mapgiao diện. Trong khi nó được đồng bộ hóa, nó dường như có vấn đề về khả năng mở rộng nghiêm trọng và không được khuyến khích cho các dự án mới.

Nhưng còn hai người kia thì sao? Sự khác biệt giữa Bản đồ được trả về Collections.synchronizedMap(Map)ConcurrentHashMaps là gì? Cái nào phù hợp với tình huống nào?


7
@SmilesinaJar liên kết hiện đang bị hỏng, đây là một bản sao lưu trữ của bài viết này: Tại sao ConcurrentHashMap là tốt hơn so với Hashtable và cũng chẳng thua kém một HashMap
informatik01

2
IBM: Làm thế nào ConcảnHashMap cung cấp đồng thời cao hơn mà không ảnh hưởng đến an toàn của luồng @ ibm.com/developerworks/java/l
Library / j

FYI, Java 6 mang đến ConcurrentSkipListMapnhư một Maptriển khai an toàn luồng khác . Được thiết kế để có tính đồng thời cao khi tải, sử dụng thuật toán Skip List .
Basil Bourque

Câu trả lời:


423

Đối với nhu cầu của bạn, sử dụng ConcurrentHashMap. Nó cho phép sửa đổi đồng thời Bản đồ từ một số luồng mà không cần phải chặn chúng. Collections.synchronizedMap(map)tạo ra một Bản đồ chặn sẽ làm giảm hiệu suất, mặc dù đảm bảo tính nhất quán (nếu được sử dụng đúng cách).

Sử dụng tùy chọn thứ hai nếu bạn cần đảm bảo tính nhất quán của dữ liệu và mỗi luồng cần có chế độ xem cập nhật trên bản đồ. Sử dụng đầu tiên nếu hiệu suất là quan trọng và mỗi luồng chỉ chèn dữ liệu vào bản đồ, với việc đọc xảy ra ít thường xuyên hơn.


8
Nhìn vào mã nguồn, bản đồ được đồng bộ hóa chỉ là một triển khai với một mutex (chặn) trong khi
ConcảnHashMap

123
Cũng xin lưu ý rằng ConcảnHashMap không cho phép các khóa hoặc giá trị null. Vì vậy, chúng KHÔNG phải là sự thay thế bằng nhau của bản đồ được đồng bộ hóa.
onejigtwojig


5
@AbdullahShaikh Vấn đề được nêu trong bài viết đó đã được sửa trong Java 7 và các cải tiến tiếp theo đã được thực hiện trong Java 8.
Pulse0ne

5
@hengxin: ngay khi bạn thực hiện thao tác bao gồm nhiều truy vấn hoặc cập nhật bản đồ hoặc khi bạn lặp lại trên bản đồ, bạn phải đồng bộ hóa thủ công trên bản đồ để đảm bảo tính nhất quán. Các bản đồ được đồng bộ hóa đảm bảo tính nhất quán chỉ cho các hoạt động đơn lẻ (yêu cầu phương thức) trên bản đồ, điều này làm cho nó thường không có giá trị vì hầu hết các hoạt động thực tế là không tầm thường nên bạn phải đồng bộ hóa thủ công.
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   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

Về cơ chế khóa: Hashtable khóa đối tượng , trong khi chỉConcurrentHashMap khóa .


13
Hashtablekhông khóa phần bản đồ. Nhìn vào việc thực hiện. Nó đang sử dụng synchronizedkhóa không có khóa được cung cấp nên về cơ bản có nghĩa là nó khóa toàn bộ hashtabletrong mỗi thao tác.
RMachnik

6
Điều gì về bản đồ được đồng bộ hóa?
Phường Samuel Edwin

3
Hành vi của Collections.syncronizedMap giống như bản đồ sao lưu, ngoại trừ tất cả các phương thức đều an toàn cho luồng
Sergii Shevchyk

5
Tôi sẽ in bảng và bán nó với giá 5 đô la mỗi cái;). Tốt một @shevchyk
realPK

Chỉnh sửa: Không phải là hoàn toàn chủ đề an toàn. Đó là một chút sai lệch cho các nhà phát triển mới hơn. Xem: ibm.com/developerworks/java/l Library / j-jtp07233 / index.html để hiểu rằng ngay cả ConcảnHashMap cũng không hoàn toàn an toàn luồng từ các cuộc đua dữ liệu bên ngoài. (ví dụ: 1 luồng loại bỏ một giá trị và một luồng khác sau đó thử kiểm tra xem nó có tồn tại hay không và đặt nó nếu không. Đó là một điều kiện chạy dữ liệu và vẫn có nghĩa là mặc dù sử dụng "ConcảnHashMap", bạn không được giảm bớt tất cả các vấn đề an toàn của luồng.
Zombie

142

"Các vấn đề về khả năng mở rộng" Hashtableđược trình bày theo cùng một cách chính xác Collections.synchronizedMap(Map)- chúng sử dụng đồng bộ hóa rất đơn giản, điều đó có nghĩa là chỉ một luồng có thể truy cập bản đồ cùng một lúc.

Đây không phải là vấn đề lớn khi bạn có các thao tác chèn và tra cứu đơn giản (trừ khi bạn thực hiện rất nhiều), nhưng trở thành một vấn đề lớn khi bạn cần lặp lại trên toàn bộ Bản đồ, có thể mất nhiều thời gian cho Bản đồ lớn - trong khi một chủ đề làm điều đó, tất cả những người khác phải chờ nếu họ muốn chèn hoặc tra cứu bất cứ điều gì.

Việc ConcurrentHashMapsử dụng các kỹ thuật rất tinh vi để giảm nhu cầu đồng bộ hóa và cho phép truy cập đọc song song bởi nhiều luồng mà không cần đồng bộ hóa và quan trọng hơn là cung cấp một Iteratoryêu cầu không đồng bộ hóa và thậm chí cho phép sửa đổi Bản đồ trong khi xen kẽ (mặc dù điều đó không đảm bảo cho dù không phải các phần tử được chèn trong quá trình lặp sẽ được trả về).


4
Bây giờ đó là những gì tôi muốn! :) Iterator không đồng bộ chỉ là sự ngọt ngào đơn thuần! Thansk cho thông tin! :) (:
Kounavi

Câu trả lời tuyệt vời..nhưng điều đó có nghĩa là trong quá trình truy xuất chủ đề sẽ không nhận được các bản cập nhật mới nhất vì các chủ đề của người đọc không được đồng bộ hóa.
MrA

@MrA: Bạn đang hỏi về ConcảnHashMap? Và bạn có ý nghĩa gì khi "thu hồi"?
Michael Borgwardt

4
@Michael Borgwardt cho đồng thờiHashmap ví dụ. giả sử có nhiều chủ đề. một số trong số họ đang cập nhật Bản đồ và một số trong số họ đang lấy dữ liệu từ cùng một bản đồ đó. Vì vậy, trong kịch bản này khi các luồng đang cố đọc thì đảm bảo rằng chúng sẽ nhận được dữ liệu mới nhất đã được cập nhật do các luồng của trình đọc không phải giữ khóa.
MrA

35

ConcảnHashMap được ưa thích khi bạn có thể sử dụng nó - mặc dù nó yêu cầu ít nhất Java 5.

Nó được thiết kế để mở rộng quy mô khi được sử dụng bởi nhiều luồng. Hiệu suất có thể kém hơn một chút khi chỉ một luồng truy cập vào Bản đồ tại một thời điểm, nhưng tốt hơn đáng kể khi nhiều luồng truy cập đồng thời trên bản đồ.

Tôi đã tìm thấy một mục blog tái tạo một bảng từ cuốn sách tuyệt vời Java Concurrency In Practice , mà tôi hoàn toàn khuyên dùng.

Bộ sưu tập.syn syncizedMap thực sự có ý nghĩa chỉ khi bạn cần bọc một bản đồ với một số đặc điểm khác, có lẽ là một loại bản đồ được sắp xếp, như Bản đồ cây.


2
Vâng - dường như tôi đề cập đến cuốn sách đó trong mọi câu trả lời khác mà tôi đưa ra!
Bill Michell

Liên kết @BillMichell bị hỏng

@Govinda Tắt javascript trước khi truy cập liên kết. Mục blog vẫn còn đó!
Bill Michell

32

Sự khác biệt chính giữa hai điều này là ConcurrentHashMapsẽ chỉ khóa một phần dữ liệu đang được cập nhật trong khi các phần khác của dữ liệu có thể được truy cập bởi các luồng khác. Tuy nhiên, Collections.synchronizedMap()sẽ khóa tất cả dữ liệu trong khi cập nhật, các luồng khác chỉ có thể truy cập dữ liệu khi khóa được phát hành. Nếu có nhiều hoạt động cập nhật và số lượng hoạt động đọc tương đối nhỏ, bạn nên chọn ConcurrentHashMap.

Ngoài ra, một điểm khác biệt nữa là ConcurrentHashMapsẽ không bảo toàn thứ tự các yếu tố trong Bản đồ được truyền vào. Nó tương tự như HashMapkhi lưu trữ dữ liệu. Không có gì đảm bảo rằng thứ tự phần tử được bảo tồn. Trong khi Collections.synchronizedMap()sẽ duy trì thứ tự các phần tử của Bản đồ được truyền vào. Ví dụ: nếu bạn chuyển a TreeMapđến ConcurrentHashMap, thứ tự các phần tử trong ConcurrentHashMapcó thể không giống với thứ tự trongTreeMap , nhưng Collections.synchronizedMap()sẽ giữ nguyên thứ tự.

Hơn nữa, ConcurrentHashMapcó thể đảm bảo rằng không có ConcurrentModificationExceptionném trong khi một luồng đang cập nhật bản đồ và một luồng khác đang đi ngang qua trình vòng lặp thu được từ bản đồ. Tuy nhiên, Collections.synchronizedMap()không được đảm bảo về điều này.

một bài viết chứng minh sự khác biệt của hai và cả ConcurrentSkipListMap.


13

Bản đồ được đồng bộ hóa:

Bản đồ được đồng bộ hóa cũng không khác lắm so với Hashtable và cung cấp hiệu năng tương tự trong các chương trình Java đồng thời. Chỉ có sự khác biệt giữa Hashtable và SyncizedMap là SyncizedMap không phải là một di sản và bạn có thể bao bọc bất kỳ Bản đồ nào để tạo phiên bản được đồng bộ hóa bằng cách sử dụng phương thức Collections.syn syncizedMap ().

Bản đồ đồng thời:

Lớp ConcảnHashMap cung cấp một phiên bản đồng thời của HashMap tiêu chuẩn. Đây là một cải tiến về chức năng syncMap được cung cấp trong lớp Bộ sưu tập.

Không giống như Hashtable và Bản đồ được đồng bộ hóa, nó không bao giờ khóa toàn bộ Bản đồ, thay vào đó, nó phân chia bản đồ theo các phân đoạn và việc khóa được thực hiện trên các bản đồ đó. Nó hoạt động tốt hơn nếu số lượng chủ đề người đọc lớn hơn số lượng chủ đề nhà văn.

Theo mặc định, concảnHashMap được phân tách thành 16 vùng và khóa được áp dụng. Số mặc định này có thể được đặt trong khi khởi tạo một thể hiện ConcảnHashMap. Khi cài đặt dữ liệu trong một phân khúc cụ thể, sẽ có được khóa cho phân đoạn đó. Điều này có nghĩa là hai bản cập nhật vẫn có thể thực hiện đồng thời một cách an toàn nếu mỗi bản cập nhật ảnh hưởng đến các nhóm riêng biệt, do đó giảm thiểu sự tranh chấp khóa và do đó tối đa hóa hiệu suất.

ConcảnHashMap không ném ra một concExModificationException

ConcảnHashMap không đưa ra một concExModificationException nếu một luồng cố gắng sửa đổi nó trong khi một luồng khác đang lặp lại trên nó

Sự khác biệt giữa synchornizedMap và ConcảnHashMap

Collections.synchornizedMap (HashMap) sẽ trả về một bộ sưu tập gần như tương đương với Hashtable, trong đó mọi thao tác sửa đổi trên Map đều bị khóa trên đối tượng Map trong khi trong trường hợp của ConcảnHashMap, an toàn luồng được thực hiện bằng cách chia toàn bộ Map thành các phân vùng khác nhau dựa trên mức độ tương tranh và chỉ khóa phần cụ thể thay vì khóa toàn bộ Bản đồ.

ConcảnHashMap không cho phép khóa null hoặc giá trị null trong khi HashMap được đồng bộ hóa cho phép một khóa null.

Liên kết tương tự

Liên kết1

Liên kết2

So sánh hiệu suất


12

Như thường lệ, có sự đánh đổi đồng thời - trên cao - tốc độ liên quan. Bạn thực sự cần phải xem xét các yêu cầu đồng thời chi tiết của ứng dụng của mình để đưa ra quyết định, sau đó kiểm tra mã của bạn để xem nó có đủ tốt không.


12

Trong ConcurrentHashMap, khóa được áp dụng cho một phân khúc thay vì toàn bộ Bản đồ. Mỗi phân đoạn quản lý bảng băm nội bộ của riêng mình. Khóa chỉ được áp dụng cho các hoạt động cập nhật. Collections.synchronizedMap(Map)đồng bộ hóa toàn bộ bản đồ.


bạn có thể vui lòng xem stackoverflow.com/questions/48579060/ trên không?
gstackoverflow

9

Bạn nói đúng về HashTable , bạn có thể quên nó.

Bài viết của bạn đề cập đến thực tế là mặc dù HashTable và lớp trình bao bọc được đồng bộ hóa cung cấp an toàn luồng cơ bản bằng cách chỉ cho phép một luồng tại một thời điểm truy cập vào bản đồ, nhưng điều này không an toàn cho luồng vì nhiều hoạt động hỗn hợp vẫn yêu cầu đồng bộ hóa bổ sung, cho thí dụ:

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

Tuy nhiên, đừng nghĩ rằng đó ConcurrentHashMaplà một thay thế đơn giản cho một khối HashMapđiển hình synchronizednhư được hiển thị ở trên. Đọc này bài viết để hiểu phức tạp của nó tốt hơn.


7

Dưới đây là một vài

1) ConcurrencyHashMap chỉ khóa một phần của Map nhưng SyncizedMap khóa toàn bộ MAp.
2) ConcảnHashMap có hiệu suất tốt hơn so với Đồng bộ hóa và có khả năng mở rộng hơn.
3) Trong trường hợp có nhiều người đọc và một người viết đơn, ConcảnHashMap là sự lựa chọn tốt nhất.

Văn bản này là từ Sự khác biệt giữa ConcảnHashMap và hàm băm trong Java


7

Chúng ta có thể đạt được sự an toàn của luồng bằng cách sử dụng ConcảnHashMap và syncisedHashmap và Hashtable. Nhưng có rất nhiều sự khác biệt nếu bạn nhìn vào kiến ​​trúc của họ.

  1. đồng bộ hóaHashmap và Hashtable

Cả hai sẽ duy trì khóa ở cấp đối tượng. Vì vậy, nếu bạn muốn thực hiện bất kỳ thao tác nào như đặt / nhận thì trước tiên bạn phải có được khóa. Đồng thời, các luồng khác không được phép thực hiện bất kỳ hoạt động nào. Vì vậy, tại một thời điểm, chỉ có một luồng có thể hoạt động trên này. Vì vậy, thời gian chờ đợi sẽ tăng lên ở đây. Chúng tôi có thể nói rằng hiệu suất tương đối thấp khi bạn so sánh với ConcảnHashMap.

  1. Bản đồ đồng thời

Nó sẽ duy trì khóa ở cấp phân khúc. Nó có 16 phân đoạn và duy trì mức đồng thời là 16 theo mặc định. Vì vậy, tại một thời điểm, 16 luồng có thể có thể hoạt động trên ConcảnHashMap. Hơn nữa, hoạt động đọc không yêu cầu khóa. Vì vậy, bất kỳ số lượng chủ đề có thể thực hiện một hoạt động có được trên nó.

Nếu thread1 muốn thực hiện thao tác put trong phân đoạn 2 và thread2 muốn thực hiện thao tác put trên phân khúc 4 thì nó được phép ở đây. Có nghĩa là, 16 luồng có thể thực hiện thao tác cập nhật (đặt / xóa) trên ConcảnHashMap tại một thời điểm.

Vì vậy, thời gian chờ đợi sẽ ít hơn ở đây. Do đó hiệu suất tương đối tốt hơn so với đồng bộ hóaHashmap và Hashtable.


1
, 1. Điều gì xảy ra nếu nhiều luồng cố gắng chỉnh sửa cùng một khối? 2. Điều gì xảy ra nếu nói hai luồng cố gắng đọc dữ liệu từ cùng một khối trong đó một luồng khác nếu ghi dữ liệu cùng một lúc?
prnjn

6

Bản đồ đồng thời

  • Bạn nên sử dụng ConcảnHashMap khi bạn cần đồng thời rất cao trong dự án của mình.
  • Đây là chủ đề an toàn mà không đồng bộ hóa toàn bộ bản đồ.
  • Đọc có thể xảy ra rất nhanh trong khi viết được thực hiện với một khóa.
  • Không có khóa ở cấp đối tượng.
  • Việc khóa ở mức độ chi tiết tốt hơn nhiều ở mức độ hàm băm.
  • ConcảnHashMap không đưa ra một concExModificationException nếu một luồng cố gắng sửa đổi nó trong khi một luồng khác đang lặp lại trên nó.
  • ConcảnHashMap sử dụng vô số các khóa.

Đồng bộ hóa

  • Đồng bộ hóa ở cấp Object.
  • Mỗi hoạt động đọc / ghi cần phải có được khóa.
  • Khóa toàn bộ bộ sưu tập là một chi phí hiệu suất.
  • Điều này về cơ bản chỉ cung cấp quyền truy cập vào một luồng cho toàn bộ bản đồ & chặn tất cả các luồng khác.
  • Nó có thể gây tranh cãi.
  • SyncizedHashMap trả về Iterator, không nhanh khi sửa đổi đồng thời.

nguồn


4

ConcảnHashMap được tối ưu hóa để truy cập đồng thời.

Truy cập không khóa toàn bộ bản đồ mà sử dụng chiến lược chi tiết hơn, giúp cải thiện khả năng mở rộng. Ngoài ra còn có các cải tiến chức năng đặc biệt cho truy cập đồng thời, ví dụ các trình lặp đồng thời.


4

một tính năng quan trọng cần lưu ý ConcurrentHashMapngoài tính năng tương tranh mà nó cung cấp, đó là trình lặp không an toàn . Tôi đã thấy các nhà phát triển sử dụng ConcurrentHashMapchỉ vì họ muốn chỉnh sửa mục nhập - đặt / xóa trong khi lặp qua nó. Collections.synchronizedMap(Map)không cung cấp iterator fail-safe nhưng thay vào đó nó cung cấp iterator fail-fast . các trình lặp không nhanh sử dụng ảnh chụp nhanh kích thước bản đồ không thể chỉnh sửa trong quá trình lặp.


3
  1. Nếu tính nhất quán của dữ liệu là rất quan trọng - Sử dụng Hashtable hoặc Collections.syn syncizedMap (Bản đồ).
  2. Nếu tốc độ / hiệu suất là rất quan trọng và Cập nhật dữ liệu có thể bị xâm phạm - Sử dụng ConcảnHashMap.

2

Nói chung, nếu bạn muốn sử dụng, ConcurrentHashMaphãy đảm bảo rằng bạn đã sẵn sàng bỏ lỡ 'bản cập nhật'
(nghĩa là in nội dung của HashMap không đảm bảo nó sẽ in Bản đồ cập nhật) và sử dụng API như CyclicBarrierđể đảm bảo tính nhất quán trong toàn bộ chương trình của bạn vòng đời.


1

Phương thức Collections.syn syncizedMap () đồng bộ hóa tất cả các phương thức của HashMap và giảm hiệu quả nó thành cấu trúc dữ liệu trong đó một luồng có thể nhập tại một thời điểm vì nó khóa mọi phương thức trên một khóa chung.

Trong đồng bộ hóa concienHashMap được thực hiện một chút khác nhau. Thay vì khóa mọi phương thức trên một khóa chung, ConcảnHashMap sử dụng khóa riêng cho các nhóm riêng biệt, do đó chỉ khóa một phần của Bản đồ. Theo mặc định, có 16 thùng và cũng có khóa riêng cho các thùng riêng biệt. Vì vậy, mức độ tương tranh mặc định là 16. Điều đó có nghĩa là về mặt lý thuyết, bất kỳ thời điểm nào, 16 luồng có thể truy cập vào concienHashMap nếu tất cả chúng sẽ tách các nhóm.


1

ConcảnHashMap đã được trình bày thay thế cho Hashtable trong Java 1.5 như là một phần của gói tương tranh. Với ConcảnHashMap, bạn có một sự lựa chọn tốt hơn không chỉ nếu nó có thể được sử dụng an toàn trong môi trường đa luồng đồng thời mà còn cung cấp hiệu suất tốt hơn Hashtable và Đồng bộ hóa. ConcảnHashMap hoạt động tốt hơn vì nó khóa một phần của Bản đồ. Nó cho phép các hoạt động đọc đồng thời và duy trì tính toàn vẹn bằng cách đồng bộ hóa các hoạt động ghi.

Cách thức đồng thời được thực hiện

ConcảnHashMap được phát triển thay thế Hashtable và hỗ trợ tất cả chức năng của Hashtable với khả năng bổ sung, nên được gọi là mức độ tương tranh. ConcảnHashMap cho phép nhiều người đọc đọc đồng thời mà không cần sử dụng các khối. Điều này trở nên khả thi bằng cách tách Map thành các phần khác nhau và chỉ chặn một phần của Map trong các bản cập nhật. Theo mặc định, mức độ tương tranh là 16, do đó, Map được chia thành 16 phần và mỗi phần được quản lý bởi khối riêng biệt. Điều đó có nghĩa là 16 luồng có thể hoạt động đồng thời với Map, nếu chúng hoạt động với các phần khác nhau của Map. Nó làm cho concienHashMap hoạt động hiệu quả và không làm giảm sự an toàn của luồng.

Nếu bạn quan tâm đến một số tính năng quan trọng của ConcảnHashMap và khi nào bạn nên sử dụng nhận thức này về Bản đồ - Tôi chỉ cần đặt một liên kết đến một bài viết hay - Cách sử dụng ConcảnHashMap trong Java


0

Ngoài những gì đã được đề xuất, tôi muốn đăng mã nguồn liên quan đến SynchronizedMap .

Để làm cho một Mapchủ đề an toàn, chúng ta có thể sử dụngCollections.synchronizedMap câu lệnh và nhập thể hiện bản đồ làm tham số.

Việc thực hiện synchronizedMaptrong Collectionsnhư dưới đây

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

Như bạn có thể thấy, Mapđối tượng đầu vào được bao bọc bởi SynchronizedMapđối tượng.
Hãy đi sâu vào việc thực hiện 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();}
        }
    }

Điều gì SynchronizedMapcó thể được tóm tắt là thêm một khóa duy nhất vào phương thức chính của Mapđối tượng đầu vào . Tất cả các phương thức được bảo vệ bởi khóa không thể được truy cập bởi nhiều luồng cùng một lúc. Điều đó có nghĩa là các hoạt động bình thường như putgetcó thể được thực hiện bởi một luồng cùng một lúc cho tất cả dữ liệu trongMap đối tượng.

Nó làm cho Map luồng đối tượng an toàn ngay bây giờ nhưng hiệu suất có thể trở thành một vấn đề trong một số tình huống.

Việc ConcurrentMaptriển khai phức tạp hơn nhiều, chúng ta có thể tham khảo Xây dựng HashMap tốt hơn để biết chi tiết. Tóm lại, nó đã được triển khai, xem xét cả an toàn và hiệu suất của luồng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.