Make expensive for loop multithreaded, Java - java

I have a problem which I would like to solve using Java's ExecutorService and Future classes. I am currently taking many samples from a function that is very expensive for me to compute (each sample can take several minutes) using a for loop. I have a class FunctionEvaluator that evaluates this function for me and this class is quite expensive to instantiate, since it contains a lot of internal memory, so I have made this class easily reusable with some internal counters and a reset() method. So my current situation looks like this:
int numSamples = 100;
int amountOfData = 1000000;
double[] data = new double[amountOfData];//Data comes from somewhere...
double[] results = new double[numSamples];
//a lot of memory contained inside the FunctionEvaluator class,
//expensive to intialise
FunctionEvaluator fe = new FunctionEvaluator();
for(int i=0; i<numSamples; i++) {
results[i] = fe.sampleAt(i, data);//very expensive computation
}
but I would like to get some multithreading going to speed things up. It should be easy enough, because while each sample will share whatever is inside of data, it is a read-only operation and each sample is independent of any other. Now I wouldn't be having any trouble with this since I've used Java's Future and ExecutorService before, but never in a context where the Callable had to be re-used. So in general, how would I go about setting this scenario up given that I can afford to run n instantiations of FunctionEvaluator? Something (very roughly) like this:
int numSamples = 100;
int amountOfData = 1000000;
int N = 10;
double[] data = new double[amountOfData];//Data comes from somewhere...
double[] results = new double[numSamples];
//a lot of memory contained inside the FunctionEvaluator class,
//expensive to intialise
FunctionEvaluator[] fe = new FunctionEvaluator[N];
for(int i=0; i<numSamples; i++) {
//Somehow add available FunctionEvaluators to an ExecutorService
//so that N FunctionEvaluators can run in parallel. When a
//FunctionEvaluator is finished, reset then compute a new sample
//until numSamples samples have been taken.
}
Any help would be greatly appreciated! Many thanks.
EDIT
So here is a toy example (which doesn't work :P). In this case the "expensive function" that I want to sample is just squaring an integer and the "expensive to instantiate class" that does it for me is called CallableComputation:
In TestConc.java:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class TestConc {
public static void main(String[] args) {
SquareCalculator squareCalculator = new SquareCalculator();
int numFunctionEvaluators = 2;
int numSamples = 10;
ExecutorService executor = Executors.newFixedThreadPool(2);
CallableComputation c1 = new CallableComputation(2);
CallableComputation c2 = new CallableComputation(3);
CallableComputation[] callables = new CallableComputation[numFunctionEvaluators];
Future<Integer>[] futures = (new Future[numFunctionEvaluators]);
int[] results = new int[numSamples];
for(int i=0; i<numFunctionEvaluators; i++) {
callables[i] = new CallableComputation(i);
futures[i] = executor.submit(callables[i]);
}
futures[0] = executor.submit(c1);
futures[1] = executor.submit(c2);
for(int i=numFunctionEvaluators; i<numSamples; ) {
for(int j=0; j<futures.length; j++) {
if(futures[j].isDone()) {
try {
results[i] = futures[j].get();
}
catch (InterruptedException e) {
e.printStackTrace();
}
catch (ExecutionException e) {
e.printStackTrace();
}
callables[j].set(i);
System.out.printf("Function evaluator %d given %d\n", j, i+1);
executor.submit(callables[j]);
i++;
}
}
}
executor.shutdown();
try {
executor.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e) {
e.printStackTrace();
}
for (int i=0; i<results.length; i++) {
System.out.printf("res%d=%d, ", i, results[i]);
}
System.out.println();
}
private static boolean areDone(Future<Integer>[] futures) {
for(int i=0; i<futures.length; i++) {
if(!futures[i].isDone()) {
return false;
}
}
return true;
}
private static void printFutures(Future<Integer>[] futures) {
for (int i=0; i<futures.length; i++) {
System.out.printf("f%d=%s | ", i, futures[i].isDone()?"done" : "not done");
}System.out.printf("\n");
}
}
In CallableComputation.java:
import java.util.concurrent.Callable;
public class CallableComputation implements Callable<Integer>{
int input = 0;
public CallableComputation(int input) {
this.input = input;
}
public void set(int i) {
input = i;
}
#Override
public Integer call() throws Exception {
System.out.printf("currval=%d\n", input);
Thread.sleep(500);
return input * input;
}
}

In Java8:
double[] result = IntStream.range(0, numSamples)
.parallel()
.mapToDouble(i->fe.sampleAt(i, data))
.toArray();
The question asks how to execute heavy computational functions in parallel by loading as many CPU as possible.
Exert from the Parallelism tutorial:
Parallel computing involves dividing a problem into subproblems,
solving those problems simultaneously (in parallel, with each
subproblem running in a separate thread), and then combining the
results of the solutions to the subproblems. Java SE provides the
fork/join framework, which enables you to more easily implement
parallel computing in your applications. However, with this framework,
you must specify how the problems are subdivided (partitioned). With
aggregate operations, the Java runtime performs this partitioning and
combining of solutions for you.
The actual solution includes:
IntStream.range will generate the stream of integers from 0 to numSamples.
parallel() will split the stream and execute it will all available CPU on the box.
mapToDouble() will convert the stream of integers to the stream of doubles by applying the lamba expression that will do actual work.
toArray() is a terminal operation that will aggregate the result and return it as an array.

There is no special code change required, you can use the same Callable again and again without any issue. Also, to improve efficiency, as you are saying, creating an instance of FunctionEvaluator is expensive, you can use only one instance and ensure that sampleAt is thread safe. One option is, maybe you can use all function local variables and don't modify any of the passing argument at any point of time while any of the thread is running
Please find a quick example below:
Code Snippet:
ExecutorService executor = Executors.newFixedThreadPool(2);
Callable<String> task1 = new Callable<String>(){public String call(){System.out.println(Thread.currentThread()+"currentThread");return null;}}
executor.submit(task1);
executor.submit(task1);
executor.shutdown();
Please find the screenshot below:

You can wrap each FunctionEvaluator's actual work as a Callable/Runnanle, then using a fixdThreadPool with a queue, then you just need to sumbit the target callable/runnable to the threadPool.

I would like to get some multithreading going to speed things up.
Sounds like a good idea but your code is massively over complex. #Pavel has a dead simple Java 8 solution but even without Java 8 you can make it a lot easier.
All you need to do is to submit the jobs into the executor and then call get() on each one of the Futures that are returned. A Callable class is not needed although it does make the code a lot cleaner. But you certainly don't need the arrays which are a bad pattern anyway because a typo can easily generate out-of-bounds exceptions. Stick to collections or Java 8 streams.
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
for (int i = 0; i < numSamples; i++ ) {
// start the jobs running in the background
futureList.add(executor.subject(new CallableComputation(i));
}
// shutdown executor if done submitting tasks, submitted jobs will keep running
executor.shutdown();
for (Future<Integer> future : futureList) {
// this will wait for the future to finish, it also throws some exceptions
Integer result = future.get();
// add result to a collection or something here
}

Related

Is there a easy way to parallelize a foreach loop in java? [duplicate]

This question already has answers here:
Java 8: Parallel FOR loop
(4 answers)
Closed 4 years ago.
Is there a easy way to parallelise a foreach loop in java 8 using some library stuff?
void someFunction(SomeType stuff, SomeType andStuff) {
for (Object object : lotsOfObjects)
object.doSomethingThatCanBeDoneInParallel(stuff, andStuff);
}
Multithreading is kinda painful and time consuming so i wonder if there is a simpler way to do the above using some library.
thanks.
edited in 3/06/2018
ExecutorServices is very handy indeed, I can't use shutdown() to wait because I run the thing every frame and create a new ExecutorServices every frame would be too expensive.
I ended up writing a class to parallelize a fori loop and I thought I share it with other newbies like me.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
public class ParallelForI {
public ParallelForI(int numberOfThread) {
NUMBER_OF_THREAD = numberOfThread;
executorService = Executors.newFixedThreadPool(NUMBER_OF_THREAD);
finished = new AtomicBoolean[NUMBER_OF_THREAD];
for (int i = 0; i < finished.length; i++)
finished[i] = new AtomicBoolean(true);
// true is better for waitForLastRun before any run.
}
private ExecutorService executorService;
private final int NUMBER_OF_THREAD;
private AtomicBoolean[] finished;
public void waitForLastRun() {
synchronized (this) {
/* synchronized outside the loop so other thread
can't notify when it's not waiting. */
for (int i = 0; i < NUMBER_OF_THREAD; i++) {
if (!finished[i].get()) {
i = -1;
try {
this.wait(); //
} catch (InterruptedException e) {
// do nothing and move one.
}
}
}
}
}
public void run(FunctionForI functionForI, final int MAX_I) {
for (AtomicBoolean finished : finished)
finished.set(false); // just started
for (int i = 0; i < NUMBER_OF_THREAD; i++) {
final int threadNumber = i;
executorService.submit(new Runnable() {
#Override // use lambda if you have java 8 or above
public void run() {
int iInitial = threadNumber * MAX_I / NUMBER_OF_THREAD;
int iSmallerThan;
if (threadNumber == NUMBER_OF_THREAD - 1) // last thread
iSmallerThan = MAX_I;
else
iSmallerThan = (threadNumber + 1) * MAX_I / NUMBER_OF_THREAD;
for (int i1 = iInitial; i1 < iSmallerThan; i1++) {
functionForI.run(i1);
}
finished[threadNumber].set(true);
synchronized (this) {
this.notify();
}
}
});
}
}
public interface FunctionForI {
void run(int i);
}
}
And this is the way to use it:
void someFunction(final SomeType stuff, final SomeType andStuff) {
ParallelForI parallelForI = new parallelForI(numberOfThread);
// swap numberOfThread with a suitable int
parallelForI.run(new ParallelForI.FunctionForI() {
#Override // use lambda if you have java 8 or above
public void run(int i) {
lotsOfObjects[i].doSomethingThatCanBeDoneInParallel(stuff, andStuff);
// don't have to be array.
}
}, lotsOfObjects.length); // again, don't have to be array
parallellForI.waitForLastRun(); // put this where ever you want
// You can even put this before parallelForI.run().
// Although it doesn't make sense to do that...
// Unlike shutdown() waitForLastRun() will not cause parallelForI to reject future task.
}
A solution could be to launch every task in a Thread as follows:
new Thread(() -> object.doSomethingThatCanBeDoneInParallel(stuff, andStuff)).start();
but this is not a relevant solution as Thread creation is costly, so there are mechanisms and tools to help you: the Executors class to build some pools.
Once you have the instance that will manage this, you provide it with tasks, which will run in parallel, on the number of threads you choose:
void someFunction(SomeType stuff, SomeType andStuff) {
ExecutorService exe = Executors.newFixedThreadPool(4); // 4 can be changed of course
for (Object object : lotsOfObjects) {
exe.submit(() -> object.doSomethingThatCanBeDoneInParallel(stuff, andStuff));
}
// Following lines are optional, depending if you need to wait until all tasks are finished or not
exe.shutdown();
try {
exe.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Use parallel streams. But this is not an universal solution.
For loops in java are inherently serial. There is no way to do such thing with them. With the introduction of streams though, you can parallelize the operations on a collection using them.

Parallel Processing of DTO in Java 7

I have requirement where need to process and map the DTOs with the values in for loop as below. Each of the mapping method here consumes nearly 10 minutes to complete its business logic and hence creating performance delay. I am working to refine the algorithms of business logic. However, please let me know if each of these mapping methods can be parallel processed to increase performance.
Since application is compatible only with Java 7 I cannot use streams of java 8.
for(Portfolio pf : portfolio) {
mapAddress(pf);
mapBusinessUnit(pf);
mapRelationShipDetails(pf)
--
--
--
}
You could split portfolios to different threads using either Runnable or Callable.
For example:
public class PortfolioService implements Callable<List<Portfolio>>
{
List<Portfolio> portfolios;
public PortfolioService(List<Portfolio> portfolios)
{
this.portfolios = portfolios;
}
public List<Portfolio> call()
{
for(Portfolio pf : portfolios) {
mapAddress(pf);
mapBusinessUnit(pf);
...
}
return portfolios;
}
}
However, this needs some modifications in your main class. I am using Callable here, since I don't know if you want to do something with all of these mapped Portfolios afterwards. However, if you want to let the threads do all of the work and don't need any return, use Runnable and modify the code.
1) You have to get your amount of cores:
int threads = Runtime.getRuntime().availableProcessors();
2) Now you split the workload per thread
// determine the average workload per thread
int blocksize = portfolios.size()/threads;
// doesn't always get all entries
int overlap = portfolios.size()%threads;
3) Start an ExecutorService, make a list of Future Elements, make reminder variable for old index of array slice
ExecutorService exs = Executors.newFixedThreadPool(threads);
List<Future<List<Portfoilio>>> futures = new ArrayList();
int oldIndex = 0;
4) Start threads
for(int i = 0; i<threads; i++)
{
int actualBlocksize = blocksize;
if(overlap != 0){
actualBlocksize++;
overlap--;
}
futures.add(exs.submit(new PortfolioService(portfolios.subList(oldIndex,actualBlocksize));
oldIndex = actualBlocksize;
}
5) Shutdown the ExecutorService and await it's termination
exs.shutdown();
try {exs.awaitTermination(6, TimeUnit.HOURS);}
catch (InterruptedException e) { }
6) do something with the future, if you want / have to.

Learning about Threads

I have written a simple program, that is intended to start a few threads. The threads should then pick a integer n from an integer array, use it to wait n and return the time t the thread waited back into an array for the results.
If one thread finishes it's task, it should pick the next one, that has not yet being assigned to another thread.
Of course: The order in the arrays has to be maintained, so that integers and results match.
My code runs smoothly as far I see.
However I use one line of code block I find in particular unsatisfying and hope there is a good way to fix this without changing too much:
while(Thread.activeCount() != 1); // first evil line
I kinda abuse this line to make sure all my threads finish getting all the tasks done, before I access my array with the results. I want to do that to prevent ill values, like 0.0, Null Pointer Exception... etc. (in short anything that would make an application with an actual use crash)
Any sort of constructive help is appreciated. I am also not sure, if my code still runs smoothly for very very long arrays of tasks for the threads, for example the results no longer match the order of the integer.
Any constructive help is appreciated.
First class:
public class ThreadArrayWriterTest {
int[] repitions;
int len = 0;
double[] timeConsumed;
public boolean finished() {
synchronized (repitions) {
return len <= 0;
}
}
public ThreadArrayWriterTest(int[] repitions) {
this.repitions = repitions;
this.len = repitions.length;
timeConsumed = new double[this.len];
}
public double[] returnTimes(int[] repititions, int numOfThreads, TimeConsumer timeConsumer) {
for (int i = 0; i < numOfThreads; i++) {
new Thread() {
public void run() {
while (!finished()) {
len--;
timeConsumed[len] = timeConsumer.returnTimeConsumed(repititions[len]);
}
}
}.start();
}
while (Thread.activeCount() != 1) // first evil line
;
return timeConsumed;
}
public static void main(String[] args) {
long begin = System.currentTimeMillis();
int[] repitions = { 3, 1, 3, 1, 2, 1, 3, 3, 3 };
int numberOfThreads = 10;
ThreadArrayWriterTest t = new ThreadArrayWriterTest(repitions);
double[] times = t.returnTimes(repitions, numberOfThreads, new TimeConsumer());
for (double d : times) {
System.out.println(d);
}
long end = System.currentTimeMillis();
System.out.println("Total time of execution: " + (end - begin));
}
}
Second class:
public class TimeConsumer {
double returnTimeConsumed(int repitions) {
long before = System.currentTimeMillis();
for (int i = 0; i < repitions; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
long after = System.currentTimeMillis();
double ret = after - before;
System.out.println("It takes: " + ret + "ms" + " for " + repitions + " runs through the for-loop");
return ret;
}
}
The easiest way to wait for all threads to complete is to keep a Collection of them and then call Thread.join() on each one in turn.
In addition to .join() you can use ExecutorService to manage pools of threads,
An Executor that provides methods to manage termination and methods
that can produce a Future for tracking progress of one or more
asynchronous tasks.
An ExecutorService can be shut down, which will cause it to reject new
tasks. Two different methods are provided for shutting down an
ExecutorService. The shutdown() method will allow previously submitted
tasks to execute before terminating, while the shutdownNow() method
prevents waiting tasks from starting and attempts to stop currently
executing tasks. Upon termination, an executor has no tasks actively
executing, no tasks awaiting execution, and no new tasks can be
submitted. An unused ExecutorService should be shut down to allow
reclamation of its resources.
Method submit extends base method Executor.execute(Runnable) by
creating and returning a Future that can be used to cancel execution
and/or wait for completion. Methods invokeAny and invokeAll perform
the most commonly useful forms of bulk execution, executing a
collection of tasks and then waiting for at least one, or all, to
complete.
ExecutorService executorService = Executors.newFixedThreadPool(maximumNumberOfThreads);
CompletionService completionService = new ExecutorCompletionService(executorService);
for (int i = 0; i < numberOfTasks; ++i) {
completionService.take();
}
executorService.shutdown();
Plus take a look at ThreadPoolExecutor
Since java provides more advanced threading API with concurrent package, You should have look into ExecutorService, which simplifies thread management mechanism.
Simple to solution to your problem.
Use Executors API to create thread pool
static ExecutorService newFixedThreadPool(int nThreads)
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue.
Use invokeAll to wait for all tasks to complete.
Sample code:
ExecutorService service = Executors.newFixedThreadPool(10);
List<MyCallable> futureList = new ArrayList<MyCallable>();
for ( int i=0; i<12; i++){
MyCallable myCallable = new MyCallable((long)i);
futureList.add(myCallable);
}
System.out.println("Start");
try{
List<Future<Long>> futures = service.invokeAll(futureList);
for(Future<Long> future : futures){
try{
System.out.println("future.isDone = " + future.isDone());
System.out.println("future: call ="+future.get());
}
catch(Exception err1){
err1.printStackTrace();
}
}
}catch(Exception err){
err.printStackTrace();
}
service.shutdown();
Refer to this related SE question for more details on achieving the same:
wait until all threads finish their work in java

How to test something in Multi-Threaded Environment using Java [duplicate]

This question already has answers here:
How should I unit test multithreaded code?
(29 answers)
Closed 5 years ago.
How do I test something like this in multithreaded environment. I know it's gonna fail, cause this code is not thread-safe. I just wanna know how can i prove it? Creating bunch of threads and trying to add with those different threads? This code is intentionally not written properly cause of testing purposes !!!
public class Response_Unit_Manager {
private static HashMap<String, Response_Unit> Response_Unit_DB =
new HashMap<> ();
/**
*
* This subprogram adds a new Response_Unit to the data store. The
* new response unit must be valid Response_Unit object and it's ID must be
* unique (i.e., must not already exist in the data store.
*
* Exceptions Thrown: Null_Object_Exception
*/
public static void Add_Response_Unit (Response_Unit New_Unit)
throws Null_Object_Exception, Duplicate_Item_Exception {
String Unit_ID = New_Unit.Unit_ID ();
if (New_Unit == null)
throw new Null_Object_Exception ();
else if (Response_Unit_Exists (Unit_ID))
throw new Duplicate_Item_Exception (Unit_ID);
else
Response_Unit_DB.put (Unit_ID, New_Unit);
} //end Add_Response_Unit
You may get lucky and see a failure when running a test, but non-failing code doesn't mean that it's thread-safe code. The only automated ways to check thread-safety is with some static analysis tools that let you put annotations on methods/classes and scan for potential issues. For example, I know FindBugs support some annotations and does concurrency checking based on them. You should be able to apply this to your single Tester class. There is still a lot of room for improvement in the industry on this topic, but here are some current examples:
http://robertfeldt.net/publications/grahn_2010_comparing_static_analysis_tools_for_concurrency_bugs.pdf
http://homepages.inf.ed.ac.uk/dts/students/spathoulas/spathoulas.pdf
As others have noted, you can't write a test that will guarantee failure as the thread schedule might "just work out", but you can write tests that have a very low probability of passing if there are thread safety issues. For example, you're code attempts to disallow duplicate items in your DB but due to thread safety issues it can't do that. So spawn a ton of threads, have them all wait on a CountdownLatch or something to maximize your chances of triggering the race, then have them all try to insert the same item. Finally you can check that (a) all but one thread saw a Duplicate_Item_Exception and (b) Response_Unit_DB contains only a single item. For these kinds of tests you can also run it several times (in the same test) to maximize your chances of triggering the issue.
Here's an example:
#Test
public void testIsThreadSafe() {
final int NUM_ITERATIONS = 100;
for(int i = 0; i < NUM_ITERATIONS; ++i) {
oneIsThreaSafeTest();
}
}
public void oneIsThreadSafeTest() {
final int NUM_THREADS = 1000;
final int UNIT_ID = 1;
final Response_Unit_Manager manager = new Response_Unit_Manager();
ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS);
CountdownLatch allThreadsWaitOnThis = new CountdownLatch(1);
AtomicInteger numThreadsSawException = new AtomicInteger(0);
for (int i = 0; i < NUM_THREADS; ++i) {
// this is a Java 8 Lambda, if using Java 7 or less you'd use a
// class that implements Runnable
exec.submit(() -> {
allThreadsWaitOnThis.await();
// making some assumptions here about how you construct
// a Response_Unit
Response_Unit unit = new Response_Unit(UNIT_ID);
try {
manager.Add_Response_Unit(unit);
} catch (Duplicate_Item_Exception e) {
numThreadsSawException.incrementAndGet();
}
});
// release all the threads
allThreadsWaitOnThis.countdown();
// wait for them all to finish
exec.shutdown();
exec.awaitTermination(10, TimeUnits.MINUTES);
assertThat(numThreadsSawException.get()).isEqualTo(NUM_THREADS - 1);
}
You can construct similar tests for the other potential thread safety issues.
The easiest way to find errors with testing, like the one which is contained in your class, is to use a Testrunner like for example the following:
package com.anarsoft.mit;
import java.util.concurrent.atomic.AtomicInteger;
public class Test_Response_Unit_Manager implements Runnable {
private final AtomicInteger threadCount = new AtomicInteger();
public void test() throws Exception
{
for(int i = 0; i < 2 ;i++)
{
Thread thread = new Thread(this, "Thread " + i);
this.threadCount.incrementAndGet();
thread.start();
}
while( this.threadCount.get() > 0 )
{
Thread.sleep(1000);
}
Thread.sleep(10 * 1000);
}
public void run()
{
exec();
threadCount.decrementAndGet();
}
protected void exec()
{
Response_Unit_Manager.Add_Response_Unit(new Response_Unit(Thread.currentThread().getId()));
}
public static void main(String[] args) throws Exception
{
(new Test_Response_Unit_Manager()).test();
}
}
And to use a dynamic race condition detection tool like http://vmlens.com, a lightweight race condition detector. This will show you the following race conditions:
And the stacktraces leading to the bug. On the left the write and one the right the read.
http://vmlens.com works with eclipse, so it depens on the ide you are using, if its useful for you

inefficient threads in java

I currently have some problems to understand why in some cases, parallelization in Java seems infficient. In the following code, I build 4 identical tasks that are executed using a ThreadPool.
On my Core i5 (2 core, 4 thread), if I set the number of workers to 1, the computer needs around 5700ms and use 25% of the processor.
If I set the number of workers to 4, then I observe 100% of CPU usage but... the time of computation is the same: 5700ms, while I expect it to be 4 times lower.
Why? Is it normal?
(Of course my real task is more complicated, but the example seems to reproduce the problem). Thank you by advance for your answers.
Here is the code:
public class Test {
public static void main(String[] args) {
int nb_workers=1;
ExecutorService executor=Executors.newFixedThreadPool(nb_workers);
long tic=System.currentTimeMillis();
for(int i=0; i<4;i++){
WorkerTest wt=new WorkerTest();
executor.execute(wt);
}
executor.shutdown();
try {
executor.awaitTermination(1000, TimeUnit.SECONDS);
} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(System.currentTimeMillis()-tic);
}
public static class WorkerTest implements Runnable {
#Override
public void run() {
double[] array=new double[10000000];
for (int i=0;i<array.length;i++){
array[i]=Math.tanh(Math.random());
}
}
}
}
The clue is that you are calling Math.random which uses a single global instance of Random. So, all your 4 threads compete for the one resource.
Using a thread local Random object will make your execution really parallel:
Random random = new Random();
double[] array = new double[10000000];
for (int i = 0; i < array.length; i++) {
array[i] = Math.tanh(random.nextDouble());
}

Categories

Resources