Threads - our industrious little helpers in the background. 🚀 In the world of modern applications, where speed, responsiveness and parallelism matter, threads are becoming an indispensable tool. But, is it possible to create an infinite number of them? 🤔 Where does the limit lie?
In this article we will answer the questions:
A thread is a unit of execution within a process. It shares the process’s address space and resources with other threads. 🧬 We can think of it as an employee inside a company — it can run independently, but still shares resources with others.
Yes, and it's huge! 🧠💥
Each CPU core can physically execute one thread at a time (and sometimes more, with Hyper-Threading support). The more cores, the more actual parallel processing.
| Device | Number of cores | Hardware threads (logical processors) | 
|---|---|---|
| Old smartphone | 4 | 4 hardware threads (no SMT on most mobile SoCs) | 
| MacBook M4 Pro | 12 or 14 | 12 or 14 hardware threads (no Hyper-Threading/SMT) | 
| Server x64 | 32+ | 32 hardware threads (no SMT) or 64+ with SMT | 
🔎 With 1000 threads on an 8-core CPU, the system has to context switch — which slows everything down.
More threads than cores → the OS scheduler performs frequent context switches between runnable threads, which adds overhead and can hurt performance.
Example: even on a laptop with 8 hardware threads, you can start 10,000+ OS threads — most will be sleeping or waiting.
✅ Yes, because:
📦 In a nutshell:
#include <thread>
#include <iostream>
int main() {
    std::cout << "Available CPU cores:"
              << std::thread::hardware_concurrency() << std::endl;
              // hint, not a guarantee
}
    std::thread: default ~2 MiB on Tier-1 platforms (configurable via Builder::stack_size).
                -Xss, scheduler policies).
        asyncio for I/O-bound tasks or
            multiprocessing for CPU-bound work.
        std::thread spawns OS threads with a ~2 MiB default stack on Tier-1
            platforms. You can reduce it with std::thread::Builder::stack_size(...), but test carefully.
            For massive concurrency, prefer an async runtime (e.g., Tokio).
        
public class ThreadExplosion {
    public static void main(String[] args) {
        int count = 0;
        try {
            while (true) {
                new Thread(() -> {
                    try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) {}
                }).start();
                count++;
                if (count % 100 == 0)
                    System.out.println("Threads: " + count);
            }
        } catch (OutOfMemoryError e) {
            System.out.println("Thread limit reached: " + count);
        }
    }
}
    🧭 Tip: if you truly need many platform threads on the JVM, consider lowering per-thread stack size with -Xss
        (trade-off: less stack headroom).
🚨 Note: You may lock up your computer, so test this only at your own risk! 😉
| Language | Typical limits (very OS/stack-dependent) | Asynchronous / lightweight alternatives | 
|---|---|---|
| Java | Thousands of platform threads typical; depends on -Xss and OS limits. | 
            Virtual Threads (Loom) | 
| Kotlin | Same platform thread limits as Java. | Coroutines | 
| Python | OS/stack-dependent; GIL blocks CPU-parallelism in one process. | asyncio, multiprocessing | 
        
| Rust | OS threads with sizable default stacks; not ideal for “10k+” without tuning. | Tokio (async runtime) | 
| C/C++ | Feasible count varies with per-thread stacks and OS limits. | Boost::asio, manual management | 
| JavaScript | 1 main thread (+ libuv pool); CPU-bound work via Worker Threads. | async/await, Web Workers |