How to Configure a ThreadPool to Send 10 Million SMS in One Hour (Java)

The article walks through calculating the required QPS for 10 million SMS in an hour, derives a precise ThreadPoolExecutor configuration (core 200, max 500, queue 5000, 60 s keep‑alive, CallerRunsPolicy), and provides complete Spring Boot code with production tips such as pagination, retry, idempotency and rate‑limiting.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
How to Configure a ThreadPool to Send 10 Million SMS in One Hour (Java)

Calculate Core Metrics

One hour equals 3600 seconds, so sending 10,000,000 SMS requires roughly 2,778 QPS (10,000,000 ÷ 3600). The SMS gateway is I/O‑bound, so the author uses the "IO‑intensive formula": core threads = CPU cores × 2, or directly 200‑500 threads depending on response time.

Recommended ThreadPool Settings (Production Tested)

// Final ThreadPool parameters
corePoolSize: 200
maximumPoolSize: 500
queueCapacity: 5000
keepAliveTime: 60s
rejectionPolicy: CallerRunsPolicy // guarantees no SMS is dropped

Complete Runnable Code (Spring Boot + Multithreading)

1. ThreadPool Configuration Class

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;

@Configuration
public class SmsThreadPoolConfig {
    @Bean("smsSendExecutor")
    public ExecutorService smsSendExecutor() {
        // 4‑core, 8 GB server → 200‑500 threads works best
        int corePoolSize = 200;
        int maximumPoolSize = 500;
        long keepAliveTime = 60L;
        int queueCapacity = 5000;
        return new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity),
                new ThreadFactory() {
                    private int count = 0;
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(r);
                        t.setName("sms-send-thread-" + count++);
                        t.setDaemon(false);
                        return t;
                    }
                },
                new ThreadPoolExecutor.CallerRunsPolicy() // important: caller runs to avoid dropping SMS
        );
    }
}

2. SMS Sending Task

import lombok.Data;
import java.util.List;

@Data
public class SmsSendTask implements Runnable {
    // each batch sends 50 messages (adjustable)
    private List phoneList;
    private String content;

    public SmsSendTask(List phoneList, String content) {
        this.phoneList = phoneList;
        this.content = content;
    }

    @Override
    public void run() {
        try {
            for (String phone : phoneList) {
                // real SMS SDK call (your own business logic)
                sendSms(phone, content);
            }
        } catch (Exception e) {
            // failure retry / log
            e.printStackTrace();
        }
    }

    // SMS sending interface
    private void sendSms(String phone, String content) {
        // call Alibaba/Tencent/Huawei SMS SDK
        System.out.println("发送成功:" + phone + " 内容:" + content);
    }
}

3. Batch Dispatch Service (10 M SMS)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;

@Service
public class SmsBatchService {
    @Autowired
    @Qualifier("smsSendExecutor")
    private ExecutorService executorService;

    /**
     * Batch send 10 M SMS, 50 per task
     */
    public void batchSendSms() {
        // 1. Read 10 M phone numbers from DB (paged, not all at once)
        List allPhoneList = get1000MPhonesFromDB();

        // 2. Split into tasks of 50 numbers
        int batchSize = 50;
        List taskPhones = new ArrayList<>(batchSize);
        for (String phone : allPhoneList) {
            taskPhones.add(phone);
            if (taskPhones.size() == batchSize) {
                // submit to thread pool
                executorService.submit(new SmsSendTask(taskPhones, "您的验证码是:888888"));
                taskPhones = new ArrayList<>(batchSize);
            }
        }
        // handle remaining < 50
        if (!taskPhones.isEmpty()) {
            executorService.submit(new SmsSendTask(taskPhones, "您的验证码是:888888"));
        }
    }

    // Simulated DB read (real project must paginate: limit 1000 per loop)
    private List get1000MPhonesFromDB() {
        return new ArrayList<>();
    }
}

Key Parameter Explanations (Interview / Production Must‑Know)

corePoolSize=200 : I/O‑intensive workload, 200 threads comfortably support >2,500 QPS.

maximumPoolSize=500 : Provides headroom for peak load.

queueCapacity=5000 : Smoothing spikes, prevents sudden overload.

rejectionPolicy=CallerRunsPolicy : Guarantees no SMS is lost.

Why the Configuration Meets the 1‑Hour Goal

Single thread can send 10‑20 SMS per second.

200 threads therefore achieve 2,000‑4,000 SMS per second.

This exceeds the required 2,778 QPS, fully satisfying the demand.

Production Considerations

SMS SDK must support asynchronous, high‑concurrency calls.

Database reads must be paginated (e.g., 1,000 rows per query).

Implement failure‑retry logic.

Ensure idempotency to avoid duplicate sends.

Add rate‑limiting to protect the SMS provider.

Conclusion

With a 4‑core, 8 GB server, the following settings reliably finish sending 10 million SMS within one hour:

core threads: 200
max threads: 500
queue: 5000
batch size: 50

The configuration fully supports the required 2,778 QPS without dropping messages.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaperformanceConcurrencyThreadPoolspring-bootsms
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.