CopyOnWriteArrayList và subList()
CopyOnWriteArrayList là biến thể thread-safe của ArrayList. Mọi phép ghi (add, set, remove...) tạo bản sao mới của mảng nội bộ. Phù hợp khi đọc nhiều, ghi ít.
Phương thức subList(int fromIndex, int toIndex) trả về view của phần tử từ fromIndex (inclusive) đến toIndex (exclusive).
Bước 1: Tạo dự án mới
Khởi tạo project Android Studio.
Bước 2: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:id="@+id/actionEvent"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="30dp"
android:textSize="30sp" />
</LinearLayout>
Bước 3: MainActivity.java
package com.example.myapplication;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import java.util.concurrent.CopyOnWriteArrayList;
public class MainActivity extends AppCompatActivity {
private CopyOnWriteArrayList<String> copyOnWriteArrayList;
private TextView actionEvent;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
copyOnWriteArrayList = new CopyOnWriteArrayList<>();
actionEvent = findViewById(R.id.actionEvent);
copyOnWriteArrayList.add("sai");
copyOnWriteArrayList.add("ram");
copyOnWriteArrayList.add("krishna");
copyOnWriteArrayList.add("prasad");
copyOnWriteArrayList.add("ram"); // Cho phép trùng lặp (khác với Set)
actionEvent.setText("Full list: " + copyOnWriteArrayList);
actionEvent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// subList(0, 2) -> index 0, 1 (2 phần tử đầu)
actionEvent.setText("subList(0,2): " + copyOnWriteArrayList.subList(0, 2));
}
});
}
}
Kết quả
Ban đầu: [sai, ram, krishna, prasad, ram]
Sau click: [sai, ram] (2 phần tử đầu tiên)
Đặc điểm quan trọng của subList()
- Trả về view (view), không phải copy: Thay đổi qua subList ảnh hưởng list gốc và ngược lại
fromIndexinclusive,toIndexexclusive- Ném
IndexOutOfBoundsExceptionnếu index không hợp lệ - Hỗ trợ tất cả operation của List (add, remove, set... trên subList)
Ví dụ thao tác trên subList
List<String> sub = copyOnWriteArrayList.subList(1, 4); // [ram, krishna, prasad]
sub.clear(); // Xóa 3 phần tử giữa
// copyOnWriteArrayList giờ thành: [sai, ram]
sub.add("new"); // Thêm vào giữa
// copyOnWriteArrayList: [sai, new, ram]
Lưu ý hiệu năng
- Mọi thay đổi trên subList (add/remove/set) đều trigger copy toàn bộ mảng nội bộ của CopyOnWriteArrayList gốc
- Nên tránh sửa đổi lớn trên subList của CopyOnWriteArrayList
- Chỉ dùng subList để đọc hoặc duyệt (iterate)
So sánh với ArrayList thường
| Đặc điểm | ArrayList | CopyOnWriteArrayList |
|---|---|---|
| Thread-safe | Không | Có |
| subList behavior | View (linked) | View (linked) |
| Chi phí ghi | O(1) amortized | O(n) - copy mảng |
| Iterator | Fail-fast | Snapshot (không bao giờ ConcurrentModificationException) |
Khi nào dùng CopyOnWriteArrayList?
- Danh sách listener/observer (đăng ký/hủy ít, duyệt nhiều)
- Cache dữ liệu ít khi cập nhật
- Cần iterator an toàn khi có thread khác sửa đổi