Phân tích mã nguồn Vector trong Java Collections Framework

Giới thiệu

Vector là một cấu trúc dữ liệu tuyến tính trong hệ sinh thái tập hợp của Java, có cơ chế hoạt động gần như tương tự ArrayList. Một câu hỏi phỏng vấn phổ biến liên quan đến lớp này là: Sự khác biệt giữa ArrayListVector là gì?

Câu trả lời thường gặp bao gồm:

  • Vector an toàn luồng (thread-safe)
  • Cơ chế mở rộng dung lượng khác nhau: ArrayList tăng thêm 50% kích thước hiện tại, trong khi Vector tăng gấp đôi

Bài viết này sẽ kiểm chứng các điểm trên thông qua việc phân tích trực tiếp mã nguồn của Vector.

Tính an toàn luồng được đảm bảo như thế nào?

Khi xem xét mã nguồn của Vector, ta thấy rằng tất cả các phương thức thay đổi hoặc truy xuất dữ liệu đều được đánh dấu bằng từ khóa synchronized. Đây chính là lý do khiến Vector được coi là thread-safe.

Dưới đây là một số ví dụ minh họa:

Thêm phần tử

public synchronized boolean add(E item) {
    modCount++;
    add(item, elementData, elementCount);
    return true;
}

Xóa phần tử

public synchronized boolean removeElement(Object target) {
    modCount++;
    int position = indexOf(target);
    if (position >= 0) {
        removeElementAt(position);
        return true;
    }
    return false;
}

Cập nhật phần tử

public synchronized E set(int idx, E newValue) {
    if (idx >= elementCount)
        throw new ArrayIndexOutOfBoundsException(idx);

    E oldValue = elementData(idx);
    elementData[idx] = newValue;
    return oldValue;
}

Lấy phần tử

public synchronized E get(int idx) {
    if (idx >= elementCount)
        throw new ArrayIndexOutOfBoundsException(idx);

    return elementData(idx);
}

Cơ chế mở rộng dung lượng

Hàm mở rộng của Vector được triển khai như sau:

private Object[] grow(int requiredCapacity) {
    int currentSize = elementData.length;
    int expandedSize = ArraysSupport.newLength(currentSize,
            requiredCapacity - currentSize, /* mức tăng tối thiểu */
            capacityIncrement > 0 ? capacityIncrement : currentSize
                                   /* mức tăng ưa thích */);
    return elementData = Arrays.copyOf(elementData, expandedSize);
}

So với ArrayList, điểm khác biệt nằm ở tham số thứ ba của ArraysSupport.newLength. Nếu không chỉ định capacityIncrement khi khởi tạo Vector, giá trị này mặc định bằng 0. Khi đó, tham số thứ ba sẽ luôn là currentSize, dẫn đến hành vi mở rộng theo cấp số nhân — cụ thể là gấp đôi kích thước hiện tại nếu yêu cầu bộ nhớ mới không vượt quá giới hạn này.

Trường hợp kích thước cần thiết lớn hơn mức tăng mặc định, hệ thống sẽ cấp phát đúng số lượng yêu cầu, nhưng vẫn bị giới hạn bởi hằng số SOFT_MAX_ARRAY_LENGTH.

Mặc dù chi tiết triển khai sâu hơn có thể thú vị, nhưng trong thực tế, Vector hiếm khi được sử dụng do hiệu năng kém hơn so với các lựa chọn thay thế hiện đại.

Thẻ: Java Collections Framework Vector synchronized thread-safety

Đăng vào ngày 19 tháng 5 lúc 09:44