Trong hướng dẫn này, chúng ta sẽ tìm hiểu về lớp ConcurrentHashMap trong Java và các hoạt động của nó với sự trợ giúp của các ví dụ.

Các lớp ConcurrentHashMap của framework collection trong Java cung cấp một bản đồ thread-safe. Có nghĩa là, nhiều luồng có thể truy cập bản đồ cùng một lúc mà không ảnh hưởng đến tính nhất quán của các mục trong bản đồ.

Nó thực hiện ConcurrentMap interface.

1. Tạo ConcurrentHashMap

Để tạo một bản đồ băm đồng thời, java.util.concurrent.ConcurrentHashMap trước tiên chúng ta phải nhập gói nó. Khi chúng ta nhập gói, đây là cách chúng ta có thể tạo các bản đồ băm đồng thời trong Java.

// ConcurrentHashMap with capacity 8 and load factor 0.6
ConcurrentHashMap<Key, Value> numbers = new ConcurrentHashMap<>(8, 0.6f);

Trong đoạn code trên, chúng ta đã tạo một bản đồ băm đồng thời có tên con số.

Đây,

  • Key- một số nhận dạng duy nhất được sử dụng để liên kết từng phần tử (giá trị) trong bản đồ
  • Value- các yếu tố được liên kết bởi các phần tử trong bản đồ

Chú ý phần new ConcurrentHashMap<>(8, 0.6). Ở đây, tham số đầu tiên là dung lượng và tham số thứ hai là loadFactor .

  • Dung lượng – Dung lượng của bản đồ này là 8. Có nghĩa là, nó có thể lưu trữ 8 mục nhập.
  • loadFactor – Hệ số tải của bản đồ này là 0,6. Điều này có nghĩa là, bất cứ khi nào bảng băm của chúng ta được lấp đầy 60%, các mục nhập sẽ được chuyển sang một bảng băm mới có kích thước gấp đôi kích thước của bảng băm ban đầu.

Công suất mặc định và hệ số tải

Có thể tạo một bản đồ băm đồng thời mà không cần xác định dung lượng và hệ số tải của nó. Ví dụ,

// ConcurrentHashMap with default capacity and load factor
ConcurrentHashMap<Key, Value> numbers1 = new ConcurrentHashMap<>();

Theo mặc định,

  • dung lượng của bản đồ sẽ là 16
  • hệ số tải sẽ là 0,75

2. Tạo Bản đồ đồng thời từ các MAP khác

Đây là cách chúng ta có thể tạo một bản đồ băm đồng thời chứa tất cả các phần tử của các map khác.

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

class Main {
    public static void main(String[] args) {

        // Creating a hashmap of even numbers
        HashMap<String, Integer> evenNumbers = new HashMap<>();
        evenNumbers.put("Two", 2);
        evenNumbers.put("Four", 4);
        System.out.println("HashMap: " + evenNumbers);

        // Creating a concurrent hashmap from other map
        ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(evenNumbers);
        numbers.put("Three", 3);
        System.out.println("ConcurrentHashMap: " + numbers);
    }
}

Đầu ra

HashMap: {Four=4, Two=2}
ConcurrentHashMap: {Four=4, Two=2, Three=3}

3. Phương thức của ConcurrentHashMap

Các lớp ConcurrentHashMap cung cấp phương thức đó cho phép chúng ta thực hiện các hoạt động khác nhau trên bản đồ.

4. Chèn các phần tử vào ConcurrentHashMap

  • put() – chèn ánh xạ khóa / giá trị được chỉ định vào bản đồ
  • putAll() – chèn tất cả các mục từ bản đồ được chỉ định vào bản đồ này
  • putIfAbsent() – chèn ánh xạ khóa / giá trị được chỉ định vào bản đồ nếu khóa được chỉ định không có trong bản đồ

Ví dụ,

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/
import java.util.concurrent.ConcurrentHashMap;

class Main {
    public static void main(String[] args) {
        // Creating ConcurrentHashMap of even numbers
        ConcurrentHashMap<String, Integer> evenNumbers = new ConcurrentHashMap<>();

        // Using put()
        evenNumbers.put("Two", 2);
        evenNumbers.put("Four", 4);

        // Using putIfAbsent()
        evenNumbers.putIfAbsent("Six", 6);
        System.out.println("ConcurrentHashMap of even numbers: " + evenNumbers);

        //Creating ConcurrentHashMap of numbers
        ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
        numbers.put("One", 1);

        // Using putAll()
        numbers.putAll(evenNumbers);
        System.out.println("ConcurrentHashMap of numbers: " + numbers);
    }
}

Đầu ra

ConcurrentHashMap of even numbers: {Six=6, Four=4, Two=2}
ConcurrentHashMap of numbers: {Six=6, One=1, Four=-4, Two=2}

5. Truy cập các phần tử ConcurrentHashMap

1. Sử dụng entrySet(), keySet() và các giá trị()

  • entrySet() – trả về một tập hợp tất cả các ánh xạ khóa / giá trị của bản đồ
  • keySet() – trả về một tập hợp tất cả các khóa của bản đồ
  • values() – trả về một tập hợp tất cả các giá trị của bản đồ

Ví dụ,

import java.util.concurrent.ConcurrentHashMap;

class Main {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();

        numbers.put("One", 1);
        numbers.put("Two", 2);
        numbers.put("Three", 3);
        System.out.println("ConcurrentHashMap: " + numbers);

        // Using entrySet()
        System.out.println("Key/Value mappings: " + numbers.entrySet());

        // Using keySet()
        System.out.println("Keys: " + numbers.keySet());

        // Using values()
        System.out.println("Values: " + numbers.values());
    }
}

Đầu ra

ConcurrentHashMap: {One=1, Two=2, Three=3}
Key/Value mappings: [One=1, Two=2, Three=3]
Keys: [One, Two, Three]
Values: [1, 2, 3]

2. Sử dụng get() và getOrDefault()

  • get()- Trả về giá trị được liên kết với khóa được chỉ định. Trả về nullnếu không tìm thấy khóa.
  • getOrDefault()- Trả về giá trị được liên kết với khóa được chỉ định. Trả về giá trị mặc định đã chỉ định nếu không tìm thấy khóa.

Ví dụ,

import java.util.concurrent.ConcurrentHashMap;

class Main {
    public static void main(String[] args) {

        ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
        numbers.put("One", 1);
        numbers.put("Two", 2);
        numbers.put("Three", 3);
        System.out.println("ConcurrentHashMap: " + numbers);

        // Using get()
        int value1 = numbers.get("Three");
        System.out.println("Using get(): " + value1);

        // Using getOrDefault()
        int value2 = numbers.getOrDefault("Five", 5);
        System.out.println("Using getOrDefault(): " + value2);
    }
}

Đầu ra

ConcurrentHashMap: {One=1, Two=2, Three=3}
Using get(): 3
Using getOrDefault(): 5

6. Loại bỏ các phần tử ConcurrentHashMap

  • remove(key) – trả về và xóa mục nhập được liên kết với khóa được chỉ định khỏi bản đồ
  • remove(key, value) – chỉ xóa mục nhập khỏi bản đồ nếu khóa được chỉ định được ánh xạ tới giá trị được chỉ định và trả về giá trị boolean

Ví dụ,

import java.util.concurrent.ConcurrentHashMap;

class Main {
    public static void main(String[] args) {

        ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
        numbers.put("One", 1);
        numbers.put("Two", 2);
        numbers.put("Three", 3);
        System.out.println("ConcurrentHashMap: " + numbers);

        // remove method with single parameter
        int value = numbers.remove("Two");
        System.out.println("Removed value: " + value);

        // remove method with two parameters
        boolean result = numbers.remove("Three", 3);
        System.out.println("Is the entry {Three=3} removed? " + result);

        System.out.println("Updated ConcurrentHashMap: " + numbers);
    }
}

Đầu ra

ConcurrentHashMap: {One=1, Two=2, Three=3}
Removed value: 2
Is the entry {Three=3} removed? True
Updated ConcurrentHashMap: {One=1}

6. Hoạt động đồng thời hàng loạt

lớp ConcurrentHashMap cung cấp số lượng lớn các hoạt động khác nhau có thể được áp dụng một cách an toàn vào các bản đồ đồng thời.

6.1. Phương thức forEach()

forEach()lặp là phương thức trên mục và thực thi của chúng ta các hàm cụ thể.

Nó bao gồm hai tham số.

  • parallelismThreshold – Nó chỉ định rằng sau khi có bao nhiêu phần tử hoạt động trong một bản đồ được thực hiện song song.
  • transformer – Điều này sẽ biến đổi dữ liệu trước khi dữ liệu được chuyển đến hàm được chỉ định.

Ví dụ,

import java.util.concurrent.ConcurrentHashMap;

class Main {
    public static void main(String[] args) {

        ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
        numbers.put("One", 1);
        numbers.put("Two", 2);
        numbers.put("Three", 3);
        System.out.println("ConcurrentHashMap: " + numbers);

        // forEach() without transformer function
        numbers.forEach(4, (k, v) -> System.out.println("key: " + k + " value: " + v));

        // forEach() with transformer function
        System.out.print("Values are ");
        numbers.forEach(4, (k, v) -> v, (v) -> System.out.print(v + ", "));
    }
}

Đầu ra

ConcurrentHashMap: {One = 1, Two = 2, Three = 3}
key: One value: 1
key: Two value: 2
key: Three value: 3
Values are 1, 2, 3,

Trong chương trình trên, chúng ta đã sử dụng song song ngưỡng 4 . Điều này có nghĩa là nếu bản đồ chứa 4 mục nhập, hoạt động sẽ được thực hiện song song.

Biến thể của phương thức forEach()

  • forEachEntry() – thực hiện hàm được chỉ định cho mỗi mục nhập
  • forEachKey() – thực hiện hàm được chỉ định cho mỗi phím
  • forEachValue() – thực hiện hàm được chỉ định cho mỗi giá trị

6.2. phương thức search()

phương thức search() tìm kiếm bản đồ dựa trên các hàm cụ thể và lợi nhuận mục phù hợp.

Ở đây, hàm được chỉ định xác định mục nhập nào sẽ được tìm kiếm.

Nó cũng bao gồm một tham số tùy chọn song song. Ngưỡng song song chỉ định rằng sau khi có bao nhiêu phần tử trong bản đồ thì hoạt động được thực hiện song song.

Ví dụ,

import java.util.concurrent.ConcurrentHashMap;

class Main {
    public static void main(String[] args) {

        ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
        numbers.put("One", 1);
        numbers.put("Two", 2);
        numbers.put("Three", 3);
        System.out.println("ConcurrentHashMap: " + numbers);

        // Using search()
        String key = numbers.search(4, (k, v) -> {return v == 3 ? k: null;});
        System.out.println("Searched value: " + key);

    }
}

Đầu ra

ConcurrentHashMap: {One=1, Two=2, Three=3}
Searched value: Three

Các biến thể của phương thức tìm kiếm()

  • searchEntries() – hàm tìm kiếm được áp dụng cho ánh xạ khóa / giá trị
  • searchKeys() – hàm tìm kiếm chỉ được áp dụng cho các phím
  • searchValues() – hàm tìm kiếm chỉ được áp dụng cho các giá trị

6.3. Phương thức Reduce()

tích lũy phương thức reduce() (quây quần bên nhau) mỗi mục trong bản đồ. Điều này có thể được sử dụng khi chúng ta cần tất cả các mục nhập để thực hiện một tác vụ chung, chẳng hạn như thêm tất cả các giá trị của map.

Nó bao gồm hai tham số.

  • song song – Nó chỉ định rằng sau khi có bao nhiêu phần tử, các hoạt động trong một bản đồ được thực hiện song song.
  • máy biến áp – Điều này sẽ biến đổi dữ liệu trước khi dữ liệu được chuyển đến hàm được chỉ định.

Ví dụ,

import java.util.concurrent.ConcurrentHashMap;

class Main {
    public static void main(String[] args) {

        ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
        numbers.put("One", 1);
        numbers.put("Two", 2);
        numbers.put("Three", 3);
        System.out.println("ConcurrentHashMap: " + numbers);

        // Using search()
        int sum = numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1 + v2);
        System.out.println("Sum of all values: " + sum);

    }
}

Đầu ra

ConcurrentHashMap: {One=1, Two=2, Three=3}
Sum of all values: 6

Trong chương trình trên, hãy chú ý câu lệnh

numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1+v2);

Đây,

  • 4 là ngưỡng song song
  • (k, v) -> v là một hàm biến áp. Nó chỉ chuyển các ánh xạ khóa / giá trị thành các giá trị.
  • (v1, v2) -> v1 + v2l à một hàm giảm. Nó tập hợp tất cả các giá trị lại với nhau và thêm tất cả các giá trị.

Các biến thể của phương thức Reduce()

  • reduceEntries() – trả về kết quả thu thập tất cả các mục nhập bằng cách sử dụng hàm giảm thiểu đã chỉ định
  • reduceKeys() – trả về kết quả thu thập tất cả các khóa bằng cách sử dụng chức năng giảm thiểu được chỉ định
  • reduceValues() – trả về kết quả thu thập tất cả các giá trị bằng cách sử dụng hàm giảm thiểu được chỉ định

7. ConcurrentHashMap so với HashMap

Dưới đây là một số khác biệt giữa ConcurrentHashMap và HashMap ,

  • ConcurrentHashMap là một bộ sưu tập an toàn theo chủ đề . Có nghĩa là, nhiều luồng có thể truy cập và sửa đổi nó cùng một lúc.
  • ConcurrentHashMap cung cấp phương thức cho các hoạt động với số lượng lớn như forEach(), search()và reduce().

8. Tại sao dùng ConcurrentHashMap?

  • lớp ConcurrentHashMap cho phép nhiều luồng để truy cập mục của nó đồng thời.
  • Theo mặc định, bản đồ băm đồng thời được chia thành 16 đoạn . Đây là lý do tại sao 16 luồng được phép đồng thời sửa đổi bản đồ cùng một lúc. Tuy nhiên, bất kỳ số lượng chủ đề nào cũng có thể truy cập vào bản đồ tại một thời điểm.
  • phương thức putIfAbsent() sẽ không ghi đè các mục trong bản đồ nếu phím được chỉ định đã tồn tại.
  • Nó cung cấp sự đồng bộ hóa của riêng nó.

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!