Java core streaming (4 threads) is slower than non-threading

I have a quad core processor. I create 4 threads and run an intensive cpu loop, and it takes> 4 times longer than running all the procedures in one thread.

I created two projects for comparison: one with a stream and one without it. I will show the code and runtime. Just notice that a project without streaming processing looks weird, I would like to replicate the memory overhead because I was not sure how much this would affect the runtime. So, here is the code without slicing:

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 takes about 11 seconds to complete.

Here is 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 takes about 1 minute 13 seconds.

Now, in the example I'm studying, they call Thread.sleep at runtime for 50 ms. If I do this, threads will be faster if I also call Thread.sleep (50) in a non-threaded class.

This is great, I know how to make it work. But the reason I study this is because I am doing pathfinding, and I am not going to add a sleep call to something that already takes a lot of time, and I don’t need to stop and do nothing even in 1 ms (if only it will not be absolutely necessary).

So, what am I interested in, what am I missing? Do the threads really need to be euthanized or should the object wait for them to work as I expect (i.e., all four loops in parallel)?

Even if I'm just wrong, why does it take so much longer? I think the worst case scenario, it will still work after 11 seconds, it just ends in some kind of unexpected order ....

+6
source share
2 answers

The huge difference in runtime is caused by the Math.random() method. If you delve into its implementation, you will see that it uses static randomNumberGenerator , which is common to all threads. If you take one step deeper, you will notice that the execution relies on the int next(int) method, which in turn uses Random.seed , which is an AtomicLong (note that all threads use the same instance of Random !) . And now we come to AtomicLong , which is implemented through an optimistic lock - and this is a problem. Optimistic locks are not designed for high load, they suffer greatly when several threads try to access them at the same time, that a drop in performance is observed.

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

+11
source

Your problem is that you are using Math.random() . Documents on this method:

...

This method is correctly synchronized to ensure proper use by multiple threads. However, if many streams must generate pseudo-random numbers at high speed, this can reduce competition for each stream to have its own pseudo-random number generator.

(my emphasis)

So, the solution is to create a new Random for each thread.

+1
source

Source: https://habr.com/ru/post/988680/


All Articles