简体   繁体   中英

How to split Math work into worker threads Java

I'm developing a Java app that calcuates numbers to powers. I would like to take advantage of my quad core computer, as only one core is being used with this application. I've looked at different tutorials on how to syncronize threads, but I don't really get it. My code is below:

public class Bignum{

public static void main(String[] args){

    Random generator = new Random();   
    long start = System.nanoTime();   
    Random generator1 = new Random();

for (long i=0; i<9000;i++){

    int power = generator1.nextInt (17) + 2;
    int power1 = generator1.nextInt (25) + 2;
    int power2 = generator1.nextInt (72) + 2;

    BigInteger num = BigInteger.valueOf (generator.nextInt (7895) + 1);
    BigInteger num1 = BigInteger.valueOf (generator.nextInt (1250) + 1);
    BigInteger num2 = BigInteger.valueOf (generator.nextInt (9765) + 1);

    BigInteger add = num.pow(power);
    BigInteger add1 = num1.pow(power1);
    BigInteger add2 = num2.pow(power2);

    BigInteger sum = add.add(add1);

}

}
}

So, for example, how could I have one thread do this:

    int power = generator1.nextInt (17) + 2;
    int power1 = generator1.nextInt (25) + 2;
    int power2 = generator1.nextInt (72) + 2;

Another do this:

    BigInteger num = BigInteger.valueOf (generator.nextInt (7895) + 1);
    BigInteger num1 = BigInteger.valueOf (generator.nextInt (1250) + 1);
    BigInteger num2 = BigInteger.valueOf (generator.nextInt (9765) + 1);

Another this:

    BigInteger add = num.pow(power);
    BigInteger add1 = num1.pow(power1);
    BigInteger add2 = num2.pow(power2);

And the last one do this:

    BigInteger sum = add.add(add1);

How could I do that? Also, how could I still repeat that 9000 times? Thank you for your help.

In Java 8 parallel maths can be quite elegant. Code below takes advantage of the fact that "+" operation is additive, so values can be summed in any order.

So the code below create a sequence of numbers in parallel and reduces (sums) them in a single thread.

import java.math.BigInteger;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.IntStream;

import static java.math.BigInteger.valueOf;
import static java.util.concurrent.ThreadLocalRandom.current;

public class Bignum {
    public static void main(String[] args) {
        Optional<BigInteger> sum = IntStream.range(0, 9000)
            .parallel()       <-- this enables parallel execution
            .mapToObj(value -> {
                ThreadLocalRandom generator = current();

                int power = generator.nextInt(17) + 2;
                int power1 = generator.nextInt(25) + 2;
                int power2 = generator.nextInt(72) + 2;

                BigInteger num = valueOf(generator.nextInt(7895) + 1);
                BigInteger num1 = valueOf(generator.nextInt(1250) + 1);
                BigInteger num2 = valueOf(generator.nextInt(9765) + 1);

                BigInteger add = num.pow(power);
                BigInteger add1 = num1.pow(power1);
                BigInteger add2 = num2.pow(power2);

                return add.add(add1).add(add2);
            })
            .reduce(BigInteger::add);

        System.out.println(sum.get());
    }
}

So i really recommend this book to get started with java multi-threading. It's like the bible of this stuff.

That being said, you're going to need a thread pool to hold your tasks, and youre going to need to make a 'worker' class (which will become the thread) that handles what it needs to do, and properly exits/returns its value.

-Make your thread pool

ExecutorService executor = Executors.newFixedThreadPool(MAX_NUMBER_THREADS_AT_ONCE);

-Make your worker task

public static class WorkerTask implements Runnable {
    //member vars if you need em

    WorkerTask() {
        //initialize member vars if you need to
    }

    @Override
    public void run() {
            //do your work here 
    }
}

-Add tasks to the thread pool like this:

for( each task you need ){
        Runnable worker = new WorkerTask( constructor params );
        executor.execute(worker);
    }

Finally, this leaves two questions:

How do I wait for them to finish?

How do I return a value from a thread?

The fact is that both of these questions have a bunch of ways to solve which might be specific to your problem, but I think in this case you can do something simple. I recommend a global static class variable which will have global scope and be able to be accessed by all threads. Be careful here, dont edit the same values as other threads, so use something like a ConcurrentHashMap, and when a thread has its answer, just add the thread id and its answer to the hashmap. ex: concurrentMap.add(threadId, value);

To wait until all the tasks are done I usually do something like this:

executor.shutdown();  //signal that you want to shutdown executor
while(!executor.isTerminated()){
        Thread.sleep(10000);  //wait ten seconds
        System.out.println("Waiting 10 seconds");
}
// now finally traverse your value map and output your answers

I prefer working with queues for thread input and output, just see the example in the docs: http://download.java.net/jdk7/archive/b123/docs/api/java/util/concurrent/BlockingQueue.html

In general there are 2.5 reasons for using threads to begin with:

  1. In multi cpu systems
  2. when dealing with IO (monitor, mouse, keyboard, sockets, read / write files etc.)
  3. for timers

Assuming you are not doing IO and not need timers, having more threads than your system CPU is going to slow you dowwwwwwwwwwwn

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM