Nguyên Lý Thiết Kế và Quy Tắc Ghi Nhớ
Để nắm vững cấu trúc Java, việc hiểu sâu các nguyên lý nền tảng là bắt buộc. Dưới đây là tổng hợp các quy tắc quan trọng giúp tối ưu hóa quá trình học và phát triển:
1. Năm Nguyên Tắc Thiết Kế Cốt Lõi (SOLID)
- Single Responsibility Principle (SRP): Một lớp chỉ nên đảm nhiệm một trách nhiệm duy nhất.
- Open/Closed Principle (OCP): Các module phần mềm nên được mở rộng cho chức năng mới nhưng không được thay đổi mã nguồn hiện tại.
- Liskov Substitution Principle (LSP): Đối tượng con phải có thể thay thế cho đối tượng cha mà không làm sai lệch hành vi chương trình.
- Interface Segregation Principle (ISP): Nên chia nhỏ các giao diện cụ thể hơn là sử dụng một giao diện lớn, chung chung.
- Dependency Inversion Principle (DIP): Phụ thuộc vào các trừu tượng hóa chứ không phải vào các chi tiết cài đặt cụ thể.
2. Phân Loại Mẫu Thiết Kế
Mẫu thiết kế được chia thành ba nhóm chức năng chính:
- Sinh tạo (Creational): Quản lý cách thức khởi tạo đối tượng (Factory, Singleton).
- Cấu trúc (Structural): Tổ chức mối quan hệ giữa các đối tượng (Adapter, Proxy, Composite).
- Hành vi (Behavioral): Định nghĩa cách trao đổi quyền kiểm soát giữa các thành phần (Observer, Strategy).
Quản Lý Dữ Liệu và Xử Lý Giao Tiếp
3. Cấu Trúc Bộ Sưu Tập (Collections)
Dựa trên đặc tính truy xuất dữ liệu, các thư viện集合 được phân loại như sau:
- List (Danh sách): Chấp nhận giá trị trùng lặp và giữ thứ tự.
-ArrayList: Truy cập ngẫu nhiên nhanh.
-LinkedList: Chèn/xóa ở vị trí đầu/cuối hiệu quả. - Set (Tập hợp): Không chấp nhận giá trị trùng lặp.
-HashSet: Hiệu suất dựa trên băm.
-TreeSet: Tự động sắp xếp theo thứ tự. - Map (Bảng khóa-giá trị): Lưu trữ cặp key-value.
-HashMap: Tốc độ cao, không sắp xếp.
-TreeMap: Sắp xếp theo key. - Queue (Hàng đợi): Xử lý theo thứ tự FIFO.
-PriorityQueue: Xếp hàng dựa trên mức độ ưu tiên.
4. Quản Trị Đa Luồng (Concurrency)
Đảm bảo an toàn trong môi trường song song yêu cầu cơ chế đồng bộ hóa:
- synchronized: Khóa trọng lượng, đảm bảo tính nguyên tử và khả năng hiển thị trạng thái.
- volatile: Đảm bảo tính khả kiến và thứ tự, nhưng không đảm bảo tính nguyên tử.
- CAS (Compare And Swap): Phương pháp không dùng khóa để thực hiện thao tác nguyên tử hiệu suất cao.
5. Mô Hình Input/Output (IO)
Tùy chọn mô hình xử lý dòng chảy dữ liệu:
- BIO (Blocking IO): Mỗi kết nối cần một luồng riêng, hoạt động chặn.
- NIO (Non-blocking IO): Sử dụng bộ chọn (Selector) để đa truy xuất, phù hợp số lượng kết nối lớn.
- AIO (Asynchronous IO): Xử lý bất đồng bộ, hệ thống điều phối hoàn tất khi sự kiện xảy ra.
Hiển Thị Kiến Trúc và Trạng Thái Hệ Thống
Cấu Trúc Tổng Thể Java
┌──────────────────────────────────────┐
│ Lớp Ứng Dụng │
├──────────────────────────────────────┤
│ Các Mô Hình & Framework │
│ [Sinh Tạo] ── [Cấu Trúc] ── [Hành Vi]│
├──────────────────────────────────────┤
│ Thư Viện Cốt Lõi (Core API) │
│ (Collections, Concurrency, IO, Net) │
├──────────────────────────────────────┤
│ Lớp JVM │
│ Heap | Method Area | Stack │
└──────────────────────────────────────┘
Vòng Đời Của Luồng (Thread Lifecycle)
NEW --(start)--> RUNNABLE --(wait/notify)--> BLOCKED
│
(lock)
↓
TERMINATED
So Sánh Mô Hình IO
- BIO: Client → Socket → Thread → Server (Một luồng một kết nối).
- NIO: Multiple Clients → Selector → Single Thread → Server (Giảm tải luồng).
- AIO: Client → Kernel → Callback Handler (Phản hồi ngay khi OS báo hoàn tất).
Khái Niệm Ẩn Dụ và Thông Số Kỹ Thuật
Kiến thức Java có thể được hình dung qua các so sánh thực tế:
- Xây dựng ứng dụng như xây nhà: JVM là nền móng, Framework là cơ sở hạ tầng, Thiết kế mẫu là trang trí nội thất, Multithreading là đội ngũ quản vận hành.
- Mô hình kinh doanh: Singleton là Giám đốc (chỉ 1 người), Factory là dây chuyền sản xuất, Observer là bộ phận giám sát chất lượng.
- Giao thông đô thị: Luồng là xe cộ, synchronized là đèn giao thông, ThreadPool là trung tâm điều hành taxi.
Dữ Liệu Quan Trọng Cần Nhớ
| Hệ Thống | Tham Số | Giá Trị Mặc Định/Chú Thích |
|---|---|---|
| HashMap | Initial Capacity | 16 |
| HashMap | Load Factor | 0.75 |
| HashMap | Treeification Threshold | 8 (khi bucket chứa nhiều node) |
| Thread Pool | Parameters | 7 tham số cốt lõi (core size, max size, queue, ...) |
| State Threads | Total States | 6 trạng thái (NEW, RUNNABLE, ...) |
Tối Ưu Hiệu Suất Cấu Trúc Dữ Liệu
- Array-based (ArrayList): Lấy phần tử O(1), chèn/xóa O(n).
- Link-list based (LinkedList): Lấy phần tử O(n), chèn/xóa O(1) nếu biết vị trí.
- Hash-based (HashMap): Tìm kiếm trung bình O(1), xấu nhất O(n).
- Tree-based (TreeMap): Tìm kiếm/log n (log của log n) hoặc O(log n).
Xử Lý Trường Hợp Thực Tế: Giao Dịch Tốc Độ Cao
Trong bối cảnh hệ thống tài chính yêu cầu chịu tải lớn, ví dụ xử lý đơn hàng với độ trễ dưới 10ms và sẵn sàng hoạt động 99.99%:
Thiết Kế Giải Pháp Đa Luồng
Thay vì khởi tạo luồng thủ công, ta sử dụng cơ chế ThreadPoolExecutor để quản lý tài nguyên CPU và bộ nhớ hiệu quả.
public class HighThroughputOrderService {
// Khởi tạo bộ đếm số lượng luồng tối đa cho server
private static final int MAX_THREADS = Runtime.getRuntime().availableProcessors() * 2;
// Định nghĩa hàng đợi nhiệm vụ
private BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(1000);
// Cấu hình Thread Pool
private ExecutorService executorService = new ThreadPoolExecutor(
10, // Số luồng cốt lõi
MAX_THREADS, // Số luồng tối đa
60L, // Thời gian sống của luồng rảnh
TimeUnit.SECONDS,
workQueue, // Hàng đợi nhiệm vụ
new CustomThreadFactory(), // Nhà máy tạo luồng tùy chỉnh
new ThreadPoolExecutor.CallerRunsPolicy() // Chính sách từ chối
);
public void processTransaction(Order order) {
executorService.submit(() -> {
try {
long startTime = System.nanoTime();
// Thực thi logic nghiệp vụ
OrderResult result = validateAndExecute(order);
long duration = System.nanoTime() - startTime;
if (duration > 10_000_000) {
logger.warn("Giao dịch chậm vượt ngưỡng 10ms");
}
} catch (Exception e) {
handleException(e, order);
}
});
}
// Kết thúc sạch sẽ khi dừng service
public void shutdown() {
executorService.shutdown();
try {
if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) {
executorService.shutdownNow();
}
} catch (InterruptedException ie) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}