Threads are expensive. They need lot of system resources, it’s time-consuming to create them and JVM is able to manage only few of them. Therefore we need asynchronous processing, new libraries, new languages etc. At least, that’s what I am hearing from everywhere. But is it really true? Are threads really so expensive? There is only one way how to find out. Just ask the machine.
The only thing we need to do is write a simple test. We just have to create as many sleeping or waiting threads as possible and we will see when it breaks. The reason why we are interested only in waiting threads is obvious. It has no sense to create thousands of active threads if we have only few CPUs. We want to simulate a situation, when threads are waiting for database data, incoming message or other CPU unrelated tasks.
public class CreateThreads { /** * Thread class * @author Lukas Krecan * */ private static final class MyThread extends Thread { private final int number; public MyThread(int number) { this.number = number; } @Override public void run() { if (shouldPrintMessage(number)) { System.out.println("Thread no. "+number+" started."); } try { //sleep forever Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * @param args */ public static void main(String[] args) { long startTime = System.currentTimeMillis(); final int noOfThreads = 1000000; int i=0; try { for (i=0; i < noOfThreads; i++) { if (shouldPrintMessage(i)) { System.out.println("Creating thread "+i+" ("+(System.currentTimeMillis()-startTime)+"ms)"); } new MyThread(i).start(); } } catch (Throwable e) { System.out.println("Error thrown when creating thread "+i); e.printStackTrace(); } } private static boolean shouldPrintMessage(int i) { return i % 100 == 0; } }
As you can see, there is nothing special in the test. Every hundredth threads prints a message to console and all of them sleep forever. In the main method we are creating threads and when an exception is thrown, number of created threads is printed out.
Even though there is nothing special on the test, the results are really interesting and for me quite surprising. I will let you guess the results. The test is executed on my two years old laptop with Intel Core 2 Duo T8100 2.1GHz. There is 64bit Linux 2.6.31 and OpenJDK (IcedTea6 1.6.1) running on top of it.
Try to guess how many threads are created if I do not tinker with JVM arguments at all. Is it 1K? Or 10K? Or even more? Well, it's slightly more than 32K. Usually you see result like this
Creating thread 31900 (37656ms) Thread no. 31900 started. Creating thread 32000 (37736ms) Thread no. 32000 started. Creating thread 32100 (37818ms) Thread no. 32100 started. Error thrown when creating thread 32172 java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:614) at CreateThreads.main(CreateThreads.java:43)
The question is, why we can not create more threads. Are we constrained by the heap size? Or maybe stack size? No in fact, 32K is apparently Linux kernel limit. Therefore there is nothing we can do in Java, Linux is just not able to handle more threads. But I think that 32K threads is not bad at all. Please keep in mind, that you will be able to reproduce the results only on modern operating systems and JVMs. I am afraid that Windows XP results will be much worse.
Please also note, that once the threads are created and all of them sleep, the application does not consume any CPU and it consumes around 800MB of memory. I am not sure why so much memory is used, it has to be investigated.
As we have seen, in this artificial scenario threads are relatively cheap. I do not want to say, that we should not use new libraries or tools. Most of them are quite useful. The only thing I want to say is that we should think twice before prematurely optimizing our applications. Sometimes the most straightforward and easiest approach is the best.
Next time, I will try to do some more real life example with servlet container.
I recommend to play with JVM settings – the most important for amount of threads is the stacktrace frame size (-Xss). We have to use this setting on Sun Solaris to handle much more threads in production.
Mimochodem zajímaly by mě nějaká konkrétní čísla – jak moc toto nastavení pomůže. Já jsem to nikdy nepočítal (to dělali admini), ale určitě by to bylo dobré vědět trošku přesněji…
Of course it has a sense to create thousands of working threads and it’s no problem for JVM.
http://mailinator.blogspot.com/2007/01/architecture-of-mailinator.html
http://mailinator.blogspot.com/2008/03/fun-mailinator-server-stats.html
In this case the threads are handling estabilished connections, so they are active and waiting for a time slice.
@IA Yes of course, I just wanted to say that it does not make much sense to create thousands of threads that actively use CPU for most of the time. Switching overhead would be just too big.
@Izap It’s interesting that on Linux -Xss did not have any measurable impact. 32K is OS limit, you can not get over that. When I set -Xss64K everything looked same including memory consumption.
Hmm, interresting.
Windows XP, java CreateThreads:
Creating thread 5000 (1547ms)
Thread no. 5000 started.
Error thrown when creating thread 5074
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Unknown Source)
at CreateThreads.main(CreateThreads.java:42)
Ctrl+C:
Java HotSpot(TM) Client VM warning: Exception java.lang.OutOfMemoryError occurre
d dispatching signal UNKNOWN to handler- the VM may need to be forcibly terminat
ed
Don’t press ctrl+break 😀
Hmm, the same on my Windows XP machine:
Thread no. 5000 started.
Error thrown when creating thread 5091
java.lang.OutOfMemoryError: unable to create new native thread
…
Playing with -Xss has no impact.
I take it back, it has impact :).
My XPs are bit better gives me 5602 🙂
but I would be interested in knowing what is the limmiting factor here.
Error thrown when creating thread 5602
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:597)
at CreateThreads.main(CreateThreads.java:42)
BTW thanks for this idea to try
I think that on Windows XP memory is the limiting factor. Try to play with stack size (-Xss JVM argument)
Pingback: Java crumbs » Blog Archive » Cool, Tomcat is able to handle more than 13,000 concurrent connections.
Pingback: Myšlenky dne otce Fura » Blog Archive » jOpenSpace 2010
Our result is 32409 with a CentOS 5.5 in 32k !!!!
Command : java -Xss48K -jar xxxxxx.jar
Error thrown when creating thread 32409
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:614)
at CreateThreads.main(CreateThreads.java:42)
We can change the number kernal threads
echo “kernel.threads-max = 50001” >> /etc/sysctl.conf
to load the configuraton use the command sysctl -p
verify the number is written in
cat /proc/sys/kernel/threads-max
Jesus Christ, please, return your university diploma immediately, if you’ve got one from computer science. Do you know JVM internals so good that you are dead-sure that each Java thread is kernel-supported thread? No, you do not know. And if it is, JVM’s authors are as good as you are. There are so-called user-mode, or light, or green threads, which are called fibers sometimes. With JVM, you even don’t know, what kind of thread you actually run. Especially, on SMP kernel. And if you believe that several thousands thread is as good as a thread pool with just a small number of kernel-supported threads, you are terribly wrong. Java is too high-level language, which takes a lot of programming burden from programmer away. And, these are the sad results. Java programmers knows nothing about JVM internals, OS internals and hardware. They just believe they do. It is really said that a lot of programmers follow the same course.
@Expert Says : What is point here apart from saying that Java programmers are so naive?