[Java Backend Zero to Hello] BÀI 2.6: ĐA LUỒNG (MULTITHREADING)
📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 2: Java Core Nâng Cao | Bài 21/86
BÀI 2.6: ĐA LUỒNG (MULTITHREADING)
Mục tiêu
- Hiểu về Thread và đa luồng
- Tạo Thread bằng nhiều cách
- Đồng bộ hóa (synchronized)
- Sử dụng volatile, wait/notify
1. PROCESS vs THREAD
| Process | Thread |
|---|---|
| Chương trình đang chạy | Đơn vị nhỏ hơn trong process |
| Có bộ nhớ riêng | Chia sẻ bộ nhớ với thread khác |
| Tốn tài nguyên | Nhẹ hơn |
| Giao tiếp qua IPC | Giao tiếp trực tiếp |
2. TẠO THREAD
2.1 Kế thừa Thread
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread đang chạy: " + getName());
}
}
MyThread t = new MyThread();
t.start(); // Bắt đầu thread mới
2.2 Implement Runnable
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable đang chạy");
}
}
Thread t = new Thread(new MyRunnable());
t.start();
2.3 Lambda (Java 8+)
Thread t = new Thread(() -> {
System.out.println("Lambda thread");
});
t.start();
2.4 Với Callable (trả về giá trị)
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
Callable<Integer> task = () -> {
Thread.sleep(1000);
return 42;
};
FutureTask<Integer> futureTask = new FutureTask<>(task);
Thread t = new Thread(futureTask);
t.start();
Integer result = futureTask.get(); // Blocking - chờ kết quả
3. CÁC METHOD CỦA THREAD
Thread t = new Thread(() -> {
// ...
});
t.start(); // Bắt đầu thread
t.join(); // Chờ thread kết thúc
t.join(1000); // Chờ tối đa 1000ms
t.setName("MyThread"); // Đặt tên
t.setPriority(Thread.MAX_PRIORITY); // Ưu tiên 1-10
t.isAlive(); // Còn sống?
t.isDaemon(); // Là daemon?
t.interrupt(); // Ngắt thread
Daemon Thread
Thread chạy nền, JVM không chờ khi kết thúc.
Thread daemon = new Thread(() -> {
while (true) {
System.out.println("Daemon running");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
});
daemon.setDaemon(true);
daemon.start();
4. VÒNG ĐỜI CỦA THREAD
NEW → RUNNABLE → BLOCKED/WAITING/TIMED_WAITING → TERMINATED
| State | Mô tả |
|---|---|
| NEW | Mới tạo, chưa start |
| RUNNABLE | Đang chạy hoặc sẵn sàng chạy |
| BLOCKED | Chờ monitor lock |
| WAITING | Chờ vô thời hạn (wait, join) |
| TIMED_WAITING | Chờ có thời hạn (sleep, wait(timeout)) |
| TERMINATED | Đã kết thúc |
5. ĐỒNG BỘ HÓA (SYNCHRONIZATION)
5.1 Vấn đề Race Condition
class Counter {
private int count = 0;
public void increment() {
count++; // Không atomic - có thể bị lỗi
}
}
5.2 synchronized method
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
5.3 synchronized block
class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
}
5.4 static synchronized
class Counter {
private static int count = 0;
public static synchronized void increment() {
count++;
}
}
6. VOLATILE
Đảm bảo biến được đọc/ghi từ main memory (không cache).
class SharedData {
private volatile boolean running = true;
public void stop() {
running = false;
}
public void run() {
while (running) {
// Làm gì đó
}
}
}
⚠️
volatilekhông thay thếsynchronized- chỉ đảm bảo visibility, không đảm bảo atomicity.
7. WAIT, NOTIFY, NOTIFYALL
Giao tiếp giữa các thread.
class MessageQueue {
private String message;
private boolean hasMessage = false;
public synchronized void put(String message) throws InterruptedException {
while (hasMessage) {
wait(); // Chờ consumer lấy
}
this.message = message;
hasMessage = true;
notifyAll(); // Đánh thức consumer
}
public synchronized String take() throws InterruptedException {
while (!hasMessage) {
wait(); // Chờ producer put
}
String msg = message;
hasMessage = false;
notifyAll(); // Đánh thức producer
return msg;
}
}
8. PRODUCER-CONSUMER VỚI BLOCKINGQUEUE
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
// Producer
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
queue.put(i);
System.out.println("Produced: " + i);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// Consumer
Thread consumer = new Thread(() -> {
try {
while (true) {
Integer item = queue.take();
System.out.println("Consumed: " + item);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
9. BÀI TẬP THỰC HÀNH
Bài 1: In số song song
// 2 thread in số chẵn/lẻ từ 1-100
Thread oddThread = new Thread(() -> {
for (int i = 1; i <= 100; i += 2) {
System.out.println("Odd: " + i);
}
});
Thread evenThread = new Thread(() -> {
for (int i = 2; i <= 100; i += 2) {
System.out.println("Even: " + i);
}
});
oddThread.start();
evenThread.start();
Bài 2: Bank Account an toàn
class BankAccount {
private double balance;
private final Object lock = new Object();
public void deposit(double amount) {
synchronized (lock) {
balance += amount;
}
}
public boolean withdraw(double amount) {
synchronized (lock) {
if (balance < amount) return false;
balance -= amount;
return true;
}
}
public double getBalance() {
synchronized (lock) {
return balance;
}
}
}
Bài 3: Download song song
List<String> urls = Arrays.asList("url1", "url2", "url3");
List<String> results = new ArrayList<>();
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<String>> futures = urls.stream()
.map(url -> executor.submit(() -> download(url)))
.collect(Collectors.toList());
for (Future<String> future : futures) {
results.add(future.get());
}
executor.shutdown();
10. TÓM TẮT
| Khái niệm | Mô tả |
|---|---|
| Thread | Đơn vị thực thi trong process |
| Runnable | Task cho thread |
| synchronized | Đồng bộ hóa |
| volatile | Đảm bảo visibility |
| wait/notify | Giao tiếp giữa thread |
| Daemon | Thread nền |
| Race condition | Lỗi khi nhiều thread truy cập |
Bài tiếp theo: 2.7 Executor Framework
🧭 Điều Hướng Series
⬅️ Bài trước: BÀI 2.5: DATE/TIME API (Java 8+)
📋 Lộ trình tổng quan: Xem Toàn Bộ Series
➡️ Bài tiếp theo: BÀI 2.7: EXECUTOR FRAMEWORK
All rights reserved