Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it that threads 10000 start() calls take more time than 10000 run() calls?

I am doing a hello world on threads, i have created a simple thread with using the run() call (which it is just a normal method call) and a duplicate thread with using the start() call which spawns another thread to process, however, the time taken for the start() calls is more than that taken for the run() calls, which are not threaded calls, why is it so?

Start call time taken: 00:00:08:300

    long time = System.currentTimeMillis();

    for (int i = 0; i < 100000; i++) {
        Thread thread = new Thread(new Car());
        thread.setName(Integer.toString(i));
        thread.start();
    }

    long completedIn = System.currentTimeMillis() - time;

    System.out.println(DurationFormatUtils.formatDuration(completedIn,
            "HH:mm:ss:SS"));

Run call time taken: 00:00:01:366

    long time = System.currentTimeMillis();

    for (int i = 0; i < 100000; i++) {
        Thread thread = new Thread(new Car());
        thread.setName(Integer.toString(i));
        thread.run();
    }

    long completedIn = System.currentTimeMillis() - time;

    System.out.println(DurationFormatUtils.formatDuration(completedIn,
            "HH:mm:ss:SS"));
like image 294
Oh Chin Boon Avatar asked Jul 24 '11 08:07

Oh Chin Boon


1 Answers

From comment to accepted response: "Would you have any advise on this?"

Yes, do not use threads directly. Since java 5, we have the java.util.concurrent framework that allows to simplify thread and task management.

Creating a thread is costly.

That is even before the thread will run the task you want, it will have to be created, a really long process. For that very reason, we have the concept of thread pool.

Instead of creating new threads each time you want to perform a concurrent task, you first create the threads and then you send them tasks when you need too.

A thread pool as a second advantage. When the task is finished, the thread is not destroyed, but kept active to run the next task, so the thread creation cost occurs only one time, at initialization time.

So how do you use theses concepts?

First create an executor with a thread pool. To stay simple we create a thread pool with 100 threads (as you want to simulate load of 100 concurrent calls):

ExecutorService pool = Executors.newFixedThreadPool(100);

Then you'ill submit your tasks:

long time = System.currentTimeMillis();
for (int i=0; i<100000; i++) {
  pool.execute(new Car());
}

And important, you'll wait for all tasks to finish before stopping the program !!!

pool.shutdown(); //Do no longer accept new tasks.
pool.awaitTermination(1, TimeUnit.HOURS); //Wait for up to one hour for all tasks to finish.
long completedIn = System.currentTimeMillis() - time;
System.out.println(DurationFormatUtils.formatDuration(completedIn,
            "HH:mm:ss:SS"));

In your thread code you didn't wait for the threads to finish their job, in fact you measured the thread creation time, not the tasks running time.

What the code does?

The executor.execute method execute the provided task inside a thread. Here it take one of the 100 thread, and let it execute the task.

What happens if there is more than 100 tasks?

With 100 threads, you can't run more than 100 concurrent tasks. Other tasks will be queued untill one task is finished so one thread is available to execute it. This is a good way to ensure you don't create too much thread and OutOfMemory or other nasty things don't happens.

How many thread should you use?

This depend of the kind of tasks you want to execute.

If it is like a web server, you are mostly IO bound waiting for the database to get data and then for the network to send the response, your thread will be mostly waiting. So even one CPU will benefit from dozen, even hundred of threads. And even if more thread start to slow down the whole application, it allow to process the user request instead of making it wait, or just deny to respond.

If your task are CPU bound you'll want something like one task per CPU core so to maximize usage of your hardware but limit the overhead of context switches. With a 4 core hyper-threading CPU, you can go up to 8 concurrent threads.

This response is just a short introduction... You'll learn more by looking at java.util.concurrent package and reading some tutorials.

like image 142
Nicolas Bousquet Avatar answered Nov 15 '22 07:11

Nicolas Bousquet