Cả hai đều là ExecutorService do Executors factory tạo ra, nhưng phục vụ mục đích lập lịch (scheduling) và thực thi tuần tự (sequential) khác nhau.
Bảng so sánh
| Tiêu chí | ScheduledThreadPoolExecutor | SingleThreadExecutor |
|---|---|---|
| Factory method | Executors.newScheduledThreadPool(corePoolSize) | Executors.newSingleThreadExecutor() |
| Đặc điểm chính | Lên lịch chạy task sau delay hoặc định kỳ (periodic) | Thực thi task tuần tự, đảm bảo chỉ 1 task active tại một thời điểm |
| Queue | DelayedWorkQueue (priority queue theo thời gian) | LinkedBlockingQueue (unbounded FIFO) |
| Thread pool size | Fixed corePoolSize (có thể config maxPoolSize) | Luôn 1 thread (core=max=1) |
| Thread lifetime | Core threads sống vĩnh viễn (keepAliveTime=0 mặc định). Non-core threads timeout. | Thread duy nhất sống vĩnh viễn. Nếu chết do exception → tạo thread mới thay thế. |
| Phương thức đặc thù | schedule, scheduleAtFixedRate, scheduleWithFixedDelay | Chỉ có methods của ExecutorService (submit, execute, invokeAll...) |
| Use case | Cron-like jobs, periodic cleanup, heartbeat, retry với delay, rate limiting | Sequential processing, serialization point, task ordering guarantee, offloading từ main thread |
| Implements | ScheduledExecutorService (extends ExecutorService) | ExecutorService (wrapped FinalizableDelegatedExecutorService) |
Ví dụ ScheduledThreadPool
import java.util.concurrent.*;
public class ScheduledThreadPoolDemo {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
// 1. Chạy một lần sau 5 giây
scheduler.schedule(() -> System.out.println("One-shot task at " + System.currentTimeMillis()),
5, TimeUnit.SECONDS);
// 2. Chạy định kỳ: fixed-rate (bắt đầu lần sau sau period từ lần trước bắt đầu)
ScheduledFuture> fixedRate = scheduler.scheduleAtFixedRate(
() -> System.out.println("Fixed-rate: " + System.currentTimeMillis()),
2, 3, TimeUnit.SECONDS); // initialDelay=2s, period=3s
// 3. Chạy định kỳ: fixed-delay (khoảng cách giữa cuối task này và đầu task sau)
ScheduledFuture> fixedDelay = scheduler.scheduleWithFixedDelay(
() -> {
System.out.println("Fixed-delay start: " + System.currentTimeMillis());
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
System.out.println("Fixed-delay end: " + System.currentTimeMillis());
},
1, 2, TimeUnit.SECONDS); // initialDelay=1s, delay=2s
// Hủy sau 15 giây
scheduler.schedule(() -> {
fixedRate.cancel(false);
fixedDelay.cancel(false);
scheduler.shutdown();
System.out.println("Scheduler shutdown");
}, 15, TimeUnit.SECONDS);
}
}
Ví dụ SingleThreadExecutor
import java.util.concurrent.*;
public class SingleThreadExecutorDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
// Submit tasks – thực thi theo thứ tự submit (FIFO)
for (int i = 1; i <= 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " started on " + Thread.currentThread().getName());
try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
System.out.println("Task " + taskId + " finished");
return taskId * 2;
});
}
// Shutdown gracefully
executor.shutdown();
try {
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
Lưu ý quan trọng
- ScheduledThreadPool với
corePoolSize > 1 có thể chạy nhiều task song song NẾU chúng đến hạn cùng lúc. Muốn serializable scheduled tasks → dùngcorePoolSize = 1. - SingleThreadExecutor đảm bảo happens-before giữa các task (memory visibility). Task n+1 thấy tất cả write của task n.
- Cả hai đều dùng
unbounded queue→ rủi ro OOM nếu producer nhanh hơn consumer liên tục. Production nên dùngThreadPoolExecutorcustom với bounded queue + RejectedExecutionHandler. - Shutdown: Luôn gọi
shutdown()→awaitTermination()→shutdownNow()nếu cần.