Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic Java threading (4 threads) slower than non-threading

I have a four core CPU. I create 4 threads and run a cpu intensive loop, and it takes > 4x longer than running it all procedurally in one thread.

I created two projects to compare, one with threading and one without. I'll show the code and run times. Just note the reason the project without threading looks weird is I wanted to replicate the memory overhead, because I wasn't sure how much it would effect run time. So, here's the code without threading:

class TimeTest implements Runnable {
    private Thread t;
    private String name;

    TimeTest(String name) {
        this.name = name;
        System.out.println("Creating class " + name);
    }

    public void run() {
        System.out.println("Running class " + name);

        int value = 100000000;
//        try {
            while (--value > 0) {
                Math.random();
//                Thread.sleep(1);
//                System.out.println("Class " + name + " " + value);
            }
//        } catch (InterruptedException e) {
//            System.out.println("Interrupted " + name);
//        }

        System.out.println("Class " + name + " exiting...");
    }

    public void start() {
        System.out.println("Starting class " + name);

        if (t == null) {
            t = new Thread(this, name);
//            t.start();
            this.run();
        }
    }
}

public class ThreadComp {
    public static void main(String[] args) {
        TimeTest one = new TimeTest("Class-1");
        one.start();

        TimeTest two = new TimeTest("Class-2");
        two.start();

        TimeTest three = new TimeTest("Class-3");
        three.start();

        TimeTest four = new TimeTest("Class-4");
        four.start();
    }
}

This runs in about 11 seconds.

Here's the code with threading:

class RunnableTest implements Runnable {
    private Thread t;
    private String name;

    RunnableTest(String name) {
        this.name = name;
        System.out.println("Creating thread " + name);
    }

    public void run() {
        System.out.println("Running thread " + name);
        int value = 100000000;
//        try {
            while (--value > 0) {
                Math.random();
//                Thread.sleep(1);
//                System.out.println("Thread " + name + " " + value);
            }
//        } catch (InterruptedException e) {
//            System.out.println("Interrupted " + name);
//        }

        System.out.println("Thread " + name + " exiting...");
    }

    public void start() {
        System.out.println("Starting thread " + name);

        if (t == null) {
            t = new Thread(this, name);
            t.start();
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        RunnableTest one = new RunnableTest("Thread-1");
        one.start();

        RunnableTest two = new RunnableTest("Thread-2");
        two.start();

        RunnableTest three = new RunnableTest("Thread-3");
        three.start();

        RunnableTest four = new RunnableTest("Thread-4");
        four.start();
    }    
}

This runs in about 1 minute 13 seconds.

Now, in the example I'm learning from, they call Thread.sleep during the lead for 50ms. If I do this, the threads run faster IF I also call Thread.sleep(50) on the non-threaded class.

Which is great, I know how to get it to work. But the reason I'm learning this is I'm doing pathfinding, and I'm not going to add a Sleep call on something that already takes a long time and doesn't need to pause and do nothing for even 1ms (unless it absolutely has to).

So, what I'm wondering is what am I missing? Do the threads absolutely HAVE to be put to sleep or does the object have to wait in order for them to work as I intend (i.e. running all four loops in parallel)?

Even if I'm just making a mistake, why would this take so much longer? I would think worst case scenario, it would still run in 11 seconds, it would just finish in some unforeseeable order....

like image 682
user1844160 Avatar asked Jun 07 '15 23:06

user1844160


People also ask

Why using more threads makes it slower than using less threads?

Switching between threads has a cost. Synchronization between threads has a cost. Adding threads is not a magical silver bullet that will speed things up. If there is not enough parallelism in the problem to overcome the overhead of using threads, then you may very well slow down your code by adding more threads.

Is a task on 2 threads always faster than a task running on one thread?

On a single core CPU, a single process (no separate threads) is usually faster than any threading done. Threads do not magically make your CPU go any faster, it just means extra work.

Will a multithreaded solution always provide better performance than a single threaded solution?

They do not make the computer run faster. All they can do is increase the efficiency of the computer by using time that would otherwise be wasted. In certain types of processing this optimization can increase efficiency and decrease running time.

Is multithreading faster in Java?

In General: Multi threading may improve throughput of the application by using more CPU power. it depends on a lot of factors. If not, the performance depends on above factors and throughput will vary between single threaded application and multi-threading application.


1 Answers

The huge difference in execution time is caused by Math.random() method. If you will dig into its implementation you will see that it uses static randomNumberGenerator that is shared across all threads. If you go one step deeper then you will notice that execution is relying on int next(int) method, which in turn using Random.seed, which is AtomicLong (consider that all threads using the same instance of Random!). And now we are coming to AtomicLong, which is implemented through optimistic locking - and that is the issue. Optimistic locks are not designed for high load, they greatly suffer when multiple threads trying to access them simultaneously, that's the performance drop you are observing.

TL;DR: Use ThreadLocalRandom (thanks to @bayou.io for mentioning this) and enjoy the performance boost.

like image 106
user3707125 Avatar answered Oct 11 '22 20:10

user3707125