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.
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 droppedComplete 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: 50The configuration fully supports the required 2,778 QPS without dropping messages.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
