Kỹ thuật xử lý đồng bộ cho các Collection trong Java

Vấn đề an toàn luồng với ArrayList

Trong môi trường đa luồng, việc sử dụng ArrayList tiêu chuẩn có thể dẫn đến các lỗi nghiêm trọng. Cụ thể, khi nhiều thread cùng thực hiện thao tác ghi, dữ liệu có thể bị ghi đè hoặc mất mát, và thường xuyên gặp phải ngoại lệ java.util.ConcurrentModificationException.

Các giải pháp đảm bảo an toàn cho List

Để khắc phục vấn đề này, lập trình viên có thể áp dụng một trong các phương án sau:

  • Sử dụng Vector: Lớp Vector đã được đồng bộ hóa sẵn thông qua từ khóa synchronized trong các phương thức. Tuy nhiên, cách này thường gây giảm hiệu suất do khóa toàn bộ đối tượng.
  • Sử dụng Collections.synchronizedList: Bao bọc ArrayList bằng phương thức tiện ích này để tạo ra một list an toàn luồng.
  • Sử dụng CopyOnWriteArrayList: Đây là giải pháp tối ưu cho trường hợp đọc nhiều ghi ít, cơ chế sao chép mảng khi ghi giúp tránh khóa độc quyền.

Dưới đây là ví dụ minh họa việc sử dụng CopyOnWriteArrayList với ExecutorService để quản lý luồng:

Xem mã nguồn minh họa List
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadSafeListDemo {
    public static void main(String[] args) {
        List<String> dataList = new CopyOnWriteArrayList<>();
        ExecutorService pool = Executors.newFixedThreadPool(20);
        
        for (int i = 0; i < 50; i++) {
            pool.submit(() -> {
                String value = UUID.randomUUID().toString().substring(0, 4);
                dataList.add(value);
                System.out.println("Current List: " + dataList);
            });
        }
        pool.shutdown();
    }
}

Vấn đề an toàn luồng với Set

Tương tự như List, các implementation của Set như HashSet cũng không an toàn khi truy cập đồng thời. Các giải pháp thay thế bao gồm:

  • CopyOnWriteArraySet: Phù hợp cho tập hợp dữ liệu ít thay đổi.
  • Collections.synchronizedSet: Bao bọc một Set thông thường để thêm cơ chế đồng bộ.
Xem mã nguồn minh họa Set
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadSafeSetDemo {
    public static void main(String[] args) {
        Set<String> uniqueItems = new CopyOnWriteArraySet<>();
        ExecutorService pool = Executors.newFixedThreadPool(15);
        
        for (int i = 0; i < 80; i++) {
            pool.submit(() -> {
                String item = UUID.randomUUID().toString().substring(0, 4);
                uniqueItems.add(item);
                System.out.println("Current Set: " + uniqueItems);
            });
        }
        pool.shutdown();
    }
}

Vấn đề an toàn luồng với Map

HashMap không được thiết kế cho việc truy cập đồng thời. Để đảm bảo tính nhất quán dữ liệu, có thể sử dụng:

  • Collections.synchronizedMap: Đồng bộ hóa một Map tiêu chuẩn.
  • ConcurrentHashMap: Cung cấp hiệu suất cao hơn nhờ cơ chế khóa phân đoạn (hoặc CAS trong các phiên bản Java mới), cho phép nhiều thread ghi dữ liệu đồng thời mà không cần khóa toàn bộ.
Xem mã nguồn minh họa Map
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadSafeMapDemo {
    public static void main(String[] args) {
        Map<String, String> storageMap = new ConcurrentHashMap<>();
        ExecutorService pool = Executors.newFixedThreadPool(10);
        
        for (int i = 0; i < 60; i++) {
            pool.submit(() -> {
                String threadName = Thread.currentThread().getName();
                String value = UUID.randomUUID().toString().substring(0, 4);
                storageMap.put(threadName, value);
                System.out.println("Current Map: " + storageMap);
            });
        }
        pool.shutdown();
    }
}

Thẻ: Java thread-safety CopyOnWriteArrayList ConcurrentHashMap collections-framework

Đăng vào ngày 8 tháng 6 lúc 17:53