views:

270

answers:

3

File: Example1.java

public class Example1 implements Runnable {

    public void run() {
     for(int i = 0; i < 100000000; i++) {
      int x = 5;
      x = x * 4;
      x = x % 3;
      x = x + 9000;
      x = x * 923;
     }
    }

    public static void task() {
     for(int i = 0; i < 100000000; i++) {
      int x = 5;
      x = x * 4;
      x = x % 3;
      x = x + 9000;
      x = x * 923;
     }
     for(int i = 0; i < 100000000; i++) {
      int x = 9;
      x = x * 2;
      x = x % 4;
      x = x + 3241;
      x = x * 472;
     }
    }

    public static void main(String[] args) {

     long startTime = System.currentTimeMillis();
      Example1.task();
      Example1.task();
      Example1.task();
      Example1.task();
      Example1.task();
     long stopTime = System.currentTimeMillis();
     long runTime = stopTime - startTime;
     System.out.println("Run time for one thread: " + runTime);


     startTime = System.Example1();
      (new Thread(new Example1())).start();
      (new Thread(new Example2())).start();
      (new Thread(new Example1())).start();
      (new Thread(new Example2())).start();
      (new Thread(new Example1())).start();
      (new Thread(new Example2())).start();
      (new Thread(new Example1())).start();
      (new Thread(new Example2())).start();
      (new Thread(new Example1())).start();
      (new Thread(new Example2())).start();
     stopTime = System.currentTimeMillis();
     runTime = stopTime - startTime;
     System.out.println("Run time for two threads: " + runTime);


    }

}

File: Example2.java

public class Example2 implements Runnable {

    public void run() {
     for(int i = 0; i < 100000000; i++) {
      int x = 9;
      x = x * 2;
      x = x % 4;
      x = x + 3241;
      x = x * 472;
     }        
    }
}

When I run this, It outputs:

Run time for one thread: 1219

Run time for two threads: 281

or something very close.

Why is there such a difference? Why does splitting it into two threads go more than two times faster than just running it directly?

+17  A: 

You're actually not waiting for the threads to finish at all.

Once you start a thread, you must then call .join() on it to wait for it to complete. What's happening here is that all of your threads are starting and as soon as the last one has started, you clock it and then calculate the stop time. This means that your threads are still running in the background.

Edit: The reason why the first one takes so long is because you're making a series of synchronous calls, while creating a thread and starting it spawns an asynchronous task.

Edit 2: Here's a napkin sequence diagram of what happens in your first test: http://www.websequencediagrams.com/cgi-bin/cdraw?lz=TWFpbi0-RXhhbXBsZTE6IFRhc2sgc3RhcnRlZAphY3RpdmF0ZSAAGAgKACEILS0-TWFpbjogZG9uZQpkZQAYEgABWAABWAABgTFlMQo&amp;s=napkin

Here's a napkin sequence diagram of what happens in your second test: http://www.websequencediagrams.com/cgi-bin/cdraw?lz=TWFpbi0tPkFub255bW91cyBUaHJlYWQ6IFN0YXJ0IEV4YW1wbGUxLnRhc2soKQoACSYyAAEuAAFdAAGBOwCCPjoAgyIGPk1haW46ICJIb3cgbG9uZyBkaWQgdGhhdCB0YWtlPyIKAINmEC0AKwhUYXNrcyBiZWdpbiB0byBmaW5pc2guLi4gKHNvbWUgbWF5IGhhdmUgZW5kZWQgZWFybGllcikK&amp;s=napkin

Edit 3: I just realized that the second sequence diagram points all of the arrows to the /same/ thread. They are in fact DIFFERENT threads, each call.

Malaxeur
+1: WebSequenceDiagrams.com == awesome.
Juliet
+1 for the web sequence diagrams :-)
Brian Agnew
+2  A: 

The call start() on a Thread immediately returns because it just enqueues the thread. The thread itself will begin running in the background some time later.

codymanix
+1  A: 

Here is what I get with your code adding join to the threads:

Run time for one thread: 566

Run time for two threads: 294

So previous answers are correct.

EDIT: I added joins this way. You can do it better, but it doesn't matter:

    Thread[] t = new Thread[10];
    (t[0] = new Thread(new Example1())).start();
    (t[1] = new Thread(new Example2())).start();
    (t[2] = new Thread(new Example1())).start();
    (t[3] = new Thread(new Example2())).start();
    (t[4] = new Thread(new Example1())).start();
    (t[5] = new Thread(new Example2())).start();
    (t[6] = new Thread(new Example1())).start();
    (t[7] = new Thread(new Example2())).start();
    (t[8] = new Thread(new Example1())).start();
    (t[9] = new Thread(new Example2())).start();

    for (Thread t1: t) {
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

You have to join each thread. However, you don't waste your time waiting in join() because other threads are not blocked. If the thread has finished it's executution before you call to join, you just continue to next thread.

Also, what does your last comment mean?

tulskiy
Where do you add join? At the end of the list of (new Thread(new Example2())).start(); ?
827
Also, those are more the differences in speed I was expecting.
827
Yes, you have to add join at the very end of the list of starts (like this example). If you add it in between, you will wait for that thread to be complete before starting the next one (avoiding any form of parallelism at all).
Malaxeur
I meant that the difference between those two is a little less than half, which is what you would expect from splitting a two tasks between two threads.
827