Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Java

ความแตกต่างระหว่าง ScheduledThreadPool และ SingleThreadExecutor ใน Java

ทั้งคู่มาจาก Executors factory methods แต่มีจุดประสงค์และพฤติกรรมต่างกัน

ตารางเปรียบเทียบ

ลำดับหัวข้อScheduledThreadPoolSingleThreadExecutor
1วัตถุประสงค์รัน Task **ตามเวลา** (delay, periodic, fixed rate)รัน Task **แบบ Sequential** (ทีละตัว, เรียงลำดับ)
2Factory MethodExecutors.newScheduledThreadPool(n)Executors.newSingleThreadExecutor()
3Queue TypeDelayedWorkQueue (Priority queue by time)LinkedBlockingQueue (FIFO)
4Thread CountFixed core threads (n), สร้างเพิ่มได้ถ้า queue เต็ม**คงที่ 1 thread** ตลอด
5Task TypesRunnable, Callable + **ScheduledFuture**Runnable, Callable
6Schedulingschedule(), scheduleAtFixedRate(), scheduleWithFixedDelay()ไม่มี (submit แล้วรันทันทีตามลำดับ)
7Thread LifetimeCore threads อยู่ตลอด (keepAliveTime=0)Recreate thread ถ้าตาย (เพื่อรักษา sequential)
8Ordering Guaranteeไม่รับประกันลำดับ (ขึ้นกับเวลา)**รับประกัน FIFO order** อย่างเคร่งครัด
9Use CaseCron jobs, Periodic tasks, Delayed executionSequential processing, Serialization, Single-threaded context

ScheduledThreadPoolExecutor - ตัวอย่าง

import java.util.concurrent.*;

public class ScheduledThreadPoolExample {
    public static void main(String[] args) throws InterruptedException {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
        
        // 1. One-time delay: รันหลัง 3 วินาที
        scheduler.schedule(() -> System.out.println("Task 1: Run after 3s"), 3, TimeUnit.SECONDS);
        
        // 2. Fixed Rate: รันทุก 2 วินาที (เริ่มนับจากเวลาเริ่มต้น)
        // ถ้า task ใช้เวลานานกว่า period → รันซ้อนกัน (multi-thread)
        ScheduledFuture fixedRate = scheduler.scheduleAtFixedRate(
            () -> System.out.println("FixedRate: " + System.currentTimeMillis()),
            1, 2, TimeUnit.SECONDS
        );
        
        // 3. Fixed Delay: รันทุก 2 วินาที **หลังจบ task ก่อนหน้า**
        // ไม่รันซ้อนกัน มั่นใจได้ว่า gap ระหว่าง task = 2s
        ScheduledFuture fixedDelay = scheduler.scheduleWithFixedDelay(
            () -> {
                System.out.println("FixedDelay start: " + System.currentTimeMillis());
                try { Thread.sleep(1500); } catch (InterruptedException ignored) {}
                System.out.println("FixedDelay end: " + System.currentTimeMillis());
            },
            1, 2, TimeUnit.SECONDS
        );
        
        // หยุดหลัง 10 วินาที
        Thread.sleep(10000);
        fixedRate.cancel(false);
        fixedDelay.cancel(false);
        scheduler.shutdown();
    }
}

Output (ตัวอย่าง)

FixedRate: 1000
FixedDelay start: 1000
FixedDelay end: 2501
FixedRate: 3001
FixedRate: 5001
FixedDelay start: 4501
Task 1: Run after 3s
FixedDelay end: 6001
FixedRate: 7001
FixedDelay start: 8001
FixedDelay end: 9501
FixedRate: 9001

SingleThreadExecutor - ตัวอย่าง

import java.util.concurrent.*;

public class SingleThreadExecutorExample {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        
        // Submit tasks - จะรันตามลำดับ FIFO ใน thread เดียว
        Future f1 = executor.submit(() -> {
            System.out.println("Task 1 start: " + Thread.currentThread().getName());
            sleep(1000);
            System.out.println("Task 1 end");
        });
        
        Future f2 = executor.submit(() -> {
            System.out.println("Task 2 start: " + Thread.currentThread().getName());
            sleep(500);
            System.out.println("Task 2 end");
        });
        
        Future f3 = executor.submit(() -> {
            System.out.println("Task 3 start: " + Thread.currentThread().getName());
            sleep(200);
            System.out.println("Task 3 end");
        });
        
        // รอให้เสร็จทั้งหมด
        f1.get(); f2.get(); f3.get();
        executor.shutdown();
        
        System.out.println("All tasks completed sequentially");
    }
    
    static void sleep(long ms) {
        try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    }
}

Output

Task 1 start: pool-1-thread-1
Task 1 end
Task 2 start: pool-1-thread-1
Task 2 end
Task 3 start: pool-1-thread-1
Task 3 end
All tasks completed sequentially

Key Differences Deep Dive

Queue Behavior

  • ScheduledThreadPool: DelayedWorkQueue - เรียงตาม **trigger time** (priority queue)
  • SingleThreadExecutor: LinkedBlockingQueue - **FIFO** insertion order

Thread Death Handling

  • ScheduledThreadPool: Core threads ไม่ตาย (keepAliveTime=0) - thread pool size คงที่
  • SingleThreadExecutor: ถ้า thread ตาย (exception) → สร้าง thread ใหม่ทันที เพื่อรักษา sequential execution

Shutdown Behavior

// ScheduledThreadPool
scheduler.shutdown(); // รอ scheduled tasks ที่รออยู่ (ไม่รัน task ใหม่)
scheduler.shutdownNow(); // ยกเลิก scheduled tasks, return list ของ tasks ที่ยังไม่รัน

// SingleThreadExecutor
executor.shutdown(); // รอ tasks ใน queue
executor.shutdownNow(); // Interrupt running task, return remaining queue

สรุป: เลือกอะไรดี?

สถานการณ์เลือกเหตุผล
Cron job / Scheduled taskScheduledThreadPoolBuilt-in scheduling APIs
Periodic cleanup / HeartbeatScheduledThreadPoolFixed rate/delay scheduling
Task queue ที่ต้องรันทีละตัวเรียงลำดับSingleThreadExecutorStrict FIFO, single thread
Serialization / Non-thread-safe resourceSingleThreadExecutorConfine access to 1 thread
Event loop patternSingleThreadExecutorSequential event processing
Delayed one-time tasksScheduledThreadPoolschedule(delay)

Modern Alternative: ScheduledExecutorService vs CompletableFuture

// Java 9+ - ใช้ CompletableFuture สำหรับ delayed task แบบง่าย
CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS)
    .execute(() -> System.out.println("Run after 5 seconds"));

// หรือ ScheduledExecutorService จาก Executors.newSingleThreadScheduledExecutor()
// รวมคุณสมบัติทั้งสอง: Single thread + Scheduling