Trang chủHướng dẫnConcurrentHashMap trong Java: Tính năng và ứng dụng thực tế
Java

ConcurrentHashMap trong Java: Tính năng và ứng dụng thực tế

CyStack blog 3 phút để đọc
CyStack blog11/07/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 3 minutes

ConcurrentHashMap trong Java là một class trong Concurrency Collection. Nó là một triển khai của hash table (bảng băm), hỗ trợ truy xuất và cập nhật đồng thời. ConcurrentHashMap được dùng trong môi trường đa luồng để tránh lỗi ConcurrentModificationException.

ConcurrentHashMap trong Java

ConcurrentHashMap

Nếu ta cố gắng chỉnh sửa một collection trong khi đang duyệt qua nó, ta sẽ gặp lỗi ConcurrentModificationException. Java 1.5 đã bổ sung các class Concurrent trong gói java.util.concurrent để giải quyết vấn đề này.

ConcurrentHashMap là một triển khai của Map, cho phép chúng ta chỉnh sửa Map ngay cả trong lúc duyệt nó. Các thao tác trên ConcurrentHashMap đều có tính an toàn luồng. ConcurrentHashMap không cho phép key và value có giá trị là null.

Ví dụ về ConcurrentHashMap trong Java

Class ConcurrentHashMap tương tự như HashMap, chỉ khác ở chỗ nó có tính an toàn luồng và cho phép chỉnh sửa collection ngay trong khi duyệt.

package com.journaldev.util;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {

	public static void main(String[] args) {

		//ConcurrentHashMap
		Map<String,String> myMap = new ConcurrentHashMap<String,String>();
		myMap.put("1", "1");
		myMap.put("2", "1");
		myMap.put("3", "1");
		myMap.put("4", "1");
		myMap.put("5", "1");
		myMap.put("6", "1");
		System.out.println("ConcurrentHashMap before iterator: "+myMap);
		Iterator<String> it = myMap.keySet().iterator();

		while(it.hasNext()){
			String key = it.next();
			if(key.equals("3")) myMap.put(key+"new", "new3");
		}
		System.out.println("ConcurrentHashMap after iterator: "+myMap);

		//HashMap
		myMap = new HashMap<String,String>();
		myMap.put("1", "1");
		myMap.put("2", "1");
		myMap.put("3", "1");
		myMap.put("4", "1");
		myMap.put("5", "1");
		myMap.put("6", "1");
		System.out.println("HashMap before iterator: "+myMap);
		Iterator<String> it1 = myMap.keySet().iterator();

		while(it1.hasNext()){
			String key = it1.next();
			if(key.equals("3")) myMap.put(key+"new", "new3");
		}
		System.out.println("HashMap after iterator: "+myMap);
	}

}

Output:

ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}
HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
	at java.util.HashMap$KeyIterator.next(HashMap.java:828)
	at com.test.ConcurrentHashMapExample.main(ConcurrentHashMapExample.java:44)

Ta có thể thấy rõ rằng ConcurrentHashMap xử lý được việc thêm phần tử mới vào map ngay trong khi duyệt, trong khi HashMap lại gây ra lỗi . Cùng xem kỹ stack trace (thông tin các hàm gọi bị lỗi). Lỗi này được gây ra bởi câu lệnh sau.

String key = it1.next();

Điều này có nghĩa là phần tử mới đã được thêm vào HashMap, nhưng iterator (bộ lặp) lại gặp lỗi. Thực tế, iterator trên các đối tượng Collection có cơ chế fail-fast, tức là bất kỳ thay đổi nào về cấu trúc hay số lượng phần tử của collection đều sẽ gây ra lỗi ngay lập tức.

Làm sao iterator biết collection đã bị chỉnh sửa?

Ta đã lấy ra một set các key từ HashMap rồi duyệt qua set đó. HashMap có chứa một biến dùng để đếm số lần collection bị chỉnh sửa. Iterator sẽ sử dụng biến này mỗi khi ta gọi phương thức next() của nó để lấy entry tiếp theo.

/**
     * The number of times this HashMap has been structurally modified
     * Structural modifications are those that change the number of mappings in
     * the HashMap or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the HashMap fail-fast.  (See ConcurrentModificationException).
     */
    transient volatile int modCount;

Giờ hãy thay đổi code một chút để thoát khỏi vòng lặp của iterator ngay khi ta thêm một phần tử mới. Ta chỉ cần thêm một câu lệnh break ngay sau lệnh put.

if(key.equals("3")){
	myMap.put(key+"new", "new3");
	break;
}

Output với đoạn code trên như dưới:

ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}
HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
HashMap after iterator: {3=1, 2=1, 1=1, 3new=new3, 6=1, 5=1, 4=1}

Điều gì xảy ra nếu giá trị của key bị chỉnh sửa?

Sẽ ra sao nếu ta không thêm một phần tử mới mà chỉ cập nhật một cặp key-value đã tồn tại? Liệu chương trình có gây ra lỗi không**?** Hãy cùng thay đổi code trong chương trình gốc và xem thử kết quả.

//myMap.put(key+"new", "new3");
myMap.put(key, "new3");

Sẽ không có lỗi nào xảy ra, bởi vì dù collection đã bị chỉnh sửa, cấu trúc của nó vẫn được giữ nguyên.

Đọc thêm

Bạn có để ý các dấu ngoặc nhọn khi ta tạo đối tượng collection và iterator không? Chúng được gọi là generics, một tính năng rất mạnh mẽ trong việc kiểm tra kiểu (type-checking) tại lúc compile để loại bỏ lỗi ClassCastException tại lúc runtime.

Hãy tìm đọc các bài viết khác của chúng tôi để hiểu thêm về generics cũng như các câu hỏi phỏng vấn về Java Collection cũng như kiểu thiết kế Iterator trong Java.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất