Which one of these two concurrent implementations is a better faster [closed] - java

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I've two implementations of generating prime numbers in parallel. The core code is taken from another post here in Stackoverflow.
I'd like to know which one of these implementations is preferred and why? Also if there are better and faster solutions for this?
Implementation 1:
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PrimeThreads {
private static int currentPrime = 0;
public static void main(String[] args) {
Object lock = new Object();
Thread primerGenThread = new Thread(() -> {
String threadName = Thread.currentThread().getName();
System.out.println("Starting thread: " + threadName);
int currentPrimeNo = 0;
synchronized (lock) {
try {
currentPrimeNo = generateNextPrime();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Prime Number Associated with this thread " + threadName + " is: " + currentPrimeNo);
System.out.println("Completed thread: " + threadName);
});
System.out.println("****This is where the project starts*****");
Scanner reader = new Scanner(System.in);
System.out.print("Enter number of threads you want to create: ");
int n = reader.nextInt();
reader.close();
ExecutorService executor = Executors.newFixedThreadPool(n);
for(int i=1;i<=n; i++) {
executor.submit(primerGenThread);
}
executor.shutdown();
try {
executor.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("****This is where the project ends*****");
}
private static int generateNextPrime() throws InterruptedException {
long startTime = System.nanoTime();
currentPrime++;
if (currentPrime < 2) {
currentPrime = 2;
return currentPrime;
}
for (int i = 2; i < currentPrime; i++) {
if (currentPrime % i == 0) {
currentPrime++;
i = 2;
} else {
continue;
}
}
long endTime = System.nanoTime();
System.out.println("Time taken: " + (endTime - startTime) + " naoseconds.");
return currentPrime;
}
}
And implementation 2:
import java.util.Scanner;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PrimeAsyncThreads {
private static int currentPrime = 0;
public static void main(String[] args) {
System.out.println("****This is where the project starts*****");
Scanner reader = new Scanner(System.in);
System.out.print("Enter number of threads you want to create: ");
int n = reader.nextInt();
reader.close();
ExecutorService executor = Executors.newFixedThreadPool(n);
for (int i = 1; i <= n; i++) {
CompletableFuture.supplyAsync(() -> {
try {
return generateNextPrime();
} catch (InterruptedException e) {
e.printStackTrace();
}
return n;
}, executor).thenAccept(s -> System.out.println("Prime Number Associated with this thread "
+ Thread.currentThread().getName() + " is: " + currentPrime));
}
executor.shutdown();
try {
executor.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("****This is where the project ends*****");
}
private static int generateNextPrime() throws InterruptedException {
long startTime = System.nanoTime();
currentPrime++;
if (currentPrime < 2) {
currentPrime = 2;
return currentPrime;
}
for (int i = 2; i < currentPrime; i++) {
if (currentPrime % i == 0) {
currentPrime++;
i = 2;
} else {
continue;
}
}
long endTime = System.nanoTime();
System.out.println("Time taken: " + (endTime - startTime) + " naoseconds.");
return currentPrime;
}
}
Appreciate your suggestions and helps.
EDIT:
Also noticed that the second implementation does not guarantee that each thread will get a new prime. In this case sometimes multiple threads get the same value of currentPrime variable.
Thanks.

The main difference between these implementations is how they are executed.
Implempentation 1 is basically equal to a sequential execution. There is no advantage of using threads because how the synchronized block is used.
Every thread waits for the previous thread to complete before the next prime is generated.
You already noticed that Implementation 2 calculates the same prime multiple times. This is because there is no synchronization. Only the counter currentPrime is used to have some way of control which number should be considered as prime in the next thread.
Hence, both implementations are not able to calculate primes in parallel to produce a viable result.
Think about the routine. You use a value to determine if its a prime number. This value should be the input for every thread to do the calculation.
Now the only thing to consider is how to make this value thread safe to make sure it is only used once.
This can be achived, e.g. by using an Atomic variable for currentPrime.
Another improvement could be to increment currentPrime outside the generateNextPrime() method. This method could take the value as a parameter. Something like
generateNextPrime(currentPrime.incrementAndGet());

Related

Why does ExecutorService waits for all threads to complete but Completable future not? [duplicate]

This question already has an answer here:
CompletableFuture is not getting executed. If I use the ExecutorService pool it works as expected but not with the common ForkJoinPool
(1 answer)
Closed 1 year ago.
In this following code,
class MainX {
static void run(int i) {
try {
System.out.println(i + " called");
Thread.sleep(1000);
String s = "";
for (int j = 0; j < 20000; j++) {
s = s + j;
}
System.out.println(i + " completed" + " " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
int p = i;
executorService.submit(() -> MainX.run(p));
}
System.out.println("all called");
executorService.shutdown();
System.out.println("all called" + " Thr:" + Thread.currentThread().getName());
}
}
(Vs)
class MainX {
static void run(int i) {
try {
System.out.println(i + " called");
Thread.sleep(1000);
String s = "";
for (int j = 0; j < 20000; j++) {
s = s + j;
}
System.out.println(i + " completed" + " " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
int p = i;
CompletableFuture.runAsync(() -> MainX.run(p));
}
}
}
In the first case, jvm keeps on running until all the threads are completed. But in the second case, jvm and other threads are killed as soon as main thread dies.
Any reason for this?
From my viewpoint, 'CompletableFuture' does not itself execute anything, so it has no threads to wait for. It relies on other mechanisms for running stages.
'runAsync', without an Executor, runs tasks in its common ForkJoin pool, which is documented as having the behaviour you observe.
That doesn't answer your question of 'why', except to say that it's intentionally designed that way. I can only hand-wave and say that its designers likely considered it to be the best default choice.
(I concur: In code I've written, if I get to the point of program termination, what I want is for everything to just go away. In the rare case I need it to complete, I'd wait for it before exiting.)

Multithreading program doesn't finish the job correctly?

So, like the question tile. I'm trying to learn multithreading programming. I have a awkward program to hlep me understand multithreading is faster than regular execution. The programm has seven classes in one java file, one test class, three classes implement Runnable, and three regular classes. The six classes all do the same thing, counting to 10 millions and return result. My problem is the three classes using three threads to run, but they didn't return the correct counts as I expected. However the three regular classes work fine.
I really appreciate anyone can help me to understand why it happens! I using JDK 9 and Eclipse 2018-12.
import java.time.Duration;
import java.time.Instant;
class MyMultiThreadExample{
public static void main(String[] args) {
GameOne g1 = new GameOne();
GameTwo g2 = new GameTwo();
GameThree g3 = new GameThree();
Thread thread1 = new Thread(g1);
Thread thread2 = new Thread(g2);
Thread thread3 = new Thread(g3);
Instant start1 = Instant.now();
thread1.start();
thread2.start();
thread3.start();
Instant end1 = Instant.now();
long elapsed = Duration.between(start1, end1).toMillis();
int total = g1.getCount() + g2.getCount() + g3.getCount();
System.out.println("MultiThread running cost " + elapsed + " to count " + total + " times");
GameFour g4 = new GameFour();
GameFive g5 = new GameFive();
GameSix g6 = new GameSix();
Instant start2 = Instant.now();
g4.run();
g5.run();
g6.run();
Instant end2 = Instant.now();
long elapsed2 = Duration.between(start2, end2).toMillis();
int total2 = g3.getCount() + g4.getCount() + g5.getCount();
System.out.println("Sequential running cost " + elapsed2 + " to count " + total2 + " times");
}
}
class GameOne implements Runnable {
int count1 = 0;
#Override
public void run() {
for (int i = 0; i < 10000000; i++) {
// System.out.print("Game1 at round " + count + " now");
count1++;
}
}
public int getCount() {
System.out.println("GameOne counts " + count1);
return count1;
}
}
class GameTwo implements Runnable {
int count2 = 0;
#Override
public void run() {
for (int i = 0; i < 10000000; i++) {
// System.out.print("Game2 at round " + count + " now");
count2++;
}
}
public int getCount() {
System.out.println("GameTwo counts " + count2);
return count2;
}
}
class GameThree implements Runnable {
int count3 = 0;
#Override
public void run() {
for (int i = 0; i < 10000000; i++) {
// System.out.print("Game3 at round " + count + " now");
count3++;
}
}
public int getCount() {
System.out.println("GameThree counts " + count3);
return count3;
}
}
class GameFour {
int count4 = 0;
public void run() {
for (int i = 0; i < 10000000; i++) {
// System.out.print("Game3 at round " + count + " now");
count4++;
}
}
public int getCount() {
System.out.println("GameFour counts " + count4);
return count4;
}
}
class GameFive {
int count5 = 0;
public void run() {
for (int i = 0; i < 10000000; i++) {
// System.out.print("Game3 at round " + count + " now");
count5++;
}
}
public int getCount() {
System.out.println("GameFive counts " + count5);
return count5;
}
}
class GameSix {
int count6 = 0;
public void run() {
for (int i = 0; i < 10000000; i++) {
// System.out.print("Game3 at round " + count + " now");
count6++;
}
}
public int getCount() {
System.out.println("GameFive counts " + count6);
return count6;
}
}
I have a awkward program to hlep me understand multithreading is faster than regular execution.
It's important to understand this is not always the case. You should only use multiple Threads when you have long running tasks that can run in parallel. IF your tasks are short, they almost certainly will run faster by running on a single Thread as there's an overhead on creating an specially synchronizing between Threads.
With that out of the way, you are not actually measuring the correct time here.
When you call Thread.start(), it will run the relevant Runnable in parallel with the code inside your function.
To let the Threads run until they complete before proceeding, you must call Thread#join():
thread1.start();
thread2.start();
thread3.start();
// all 3 Threads may be running now, but maybe not even started!
// let's wait for them to finish running by joining them
thread1.join();
thread2.join();
thread3.join();
This is the easiest way to wait... but there are others and this is a complex topic.
You may also run into trouble as your tasks have mutable state (the count variables) and the visibility of changes from different Threads needs to be carefully managed (you can make it volatile, for example, so updates are flushed to other Threads).
To learn more about concurrency in Java, I recommend you read about it. The Baeldung tutorials are excellent.
You're forgetting to call thread.join() -- this waits until the thread finishes executing.
Otherwise you're reading the counters in the middle of the execution.
Your code should be:
thread1.start()
thread2.start()
thread3.start()
thread1.join()
thread2.join()
thread3.join()
Additionally, all your classes can be compacted into a single class Game:
class Game implements Runnable {
String name;
int count = 0;
public Game(String name) {
this.name = name;
}
#Override
public void run() {
for (int i = 0; i < 10000000; i++) {
// System.out.print(name + " at round " + count + " now");
count++;
}
}
public int getCount() {
System.out.println(name + " counts " + count);
return count;
}
}
Each will have its own counter, and you can run them in a thread or in the same thread by calling run() -- your main method remains mostly unchanged except where they're instantiated. They can be instantiated like:
Game g1 = new Game("GameOne");
Game g2 = new Game("GameTwo");
Game g3 = new Game("GameThree");
Game g4 = new Game("GameFour");
Game g5 = new Game("GameFive");
Game g6 = new Game("GameSix");

Why does it take different times to execute threads of the same behavior?

I'm new to multithreading. I have a program that consists of two classes: PrimeNumber and a main class. I'm trying to find all the prime numbers in a given range.
Here's my PrimeNumber class:
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class PrimeNumber extends Thread{
int start, end;
int threadNumber; //used to display the thread number
static ArrayList<Integer> list = new ArrayList<Integer>(1000000);
public PrimeNumber(int start, int end, int threadNumber) {
this.start = start;
this.end = end;
this.threadNumber = threadNumber;
// added code
if(list.isEmpty()){
list.add(2);
}
}
#Override
public void run(){
long startTime = System.nanoTime();
System.out.println(threadNumber + " started");
for(int i = start; i<=end;i++){
if(isPrime(i)){
list.add(i);
}
}
System.out.println(threadNumber + " has finished");
long endTime = System.nanoTime();
System.out.println("Time for thread " + threadNumber + " is " +TimeUnit.SECONDS.convert(endTime-startTime, TimeUnit.NANOSECONDS) + " seconds.");
}
//modified method
/**
* Determine whether a number is prime
* #param number
* #return true if number is prime, false otherwise
*/
public boolean isPrime(int number){
if(number == 0 || number == 1){
return false;
}
else {
int counter = 0;
while(counter<list.size()){
if(number%list.get(counter)==0){
return false;
}
counter++;
}
}
return true;
}
}
and here's my main class
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
public class MainClass {
public static void main(String[] args) throws InterruptedException{
final int maxNumberOfThreads = 3; // number of threads I want to create
final int maxNumber = 900000; // Max range for which I'm finding all the prime numbers up to it
int initialNumber = 1;
ArrayList<Thread> myList = new ArrayList<Thread>();
for(int i = 0; i < maxNumberOfThreads; i++ ){
myList.add(new PrimeNumber(initialNumber, initialNumber+ maxNumber/maxNumberOfThreads, i+1));
myList.get(i).start();
initialNumber+=maxNumber/maxNumberOfThreads;
}
for(Thread thread : myList){
thread.join();
}
try {
Collections.sort(PrimeNumber.list); // sort the list
BufferedWriter writer = new BufferedWriter(new FileWriter(new File("Primes.txt"),true));
for(int i = 0; i <PrimeNumber.list.size(); i++){
writer.write(PrimeNumber.list.get(i).toString());
//System.out.println(PrimeNumber.list.get(i));
writer.newLine();
}
writer.close();
System.out.println("Done writing to the file");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
When I run my program here's the output I get:
2 started
3 started
1 started
1 has finished
Time for thread 1 is 3 seconds.
2 has finished
Time for thread 2 is 7 seconds.
3 has finished
Time for thread 3 is 11 seconds.
Done writing to the file
Even though the threads have similar behaviors (they all calculate the prime numbers on almost identical ranges) why is the execution time different for each thread?
I've searched for quite some time but didn't find a satisfying answer. Thanks in advance.
Edit: I've added a step in my isPrime() method which improved the execution time greatly.
This loop in method isPrime performs more iterations on thread 3 than on thread 2, and more iterations on thread 2 than on thread 1, since numbers tested are different in each case:
for(int i = 2; i< number; i++)
{
if(number%i ==0){
return false;
}
}
return true;
Also, the number of primes in each of the three ranges is different, so the number of additions to the list will be different too.

How do I get my threads to utilize 100% CPU? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I have a simple Producer (1) and consumer (varying from 1-50) problem where the Producer simply adds elements in a Queue and the consumers read it. I am trying to get 100% CPU utilization.
Currently I am getting 20% utilization. And I cannot get 100% CPU utilization. I want all my CPU used to perform the operation faster. What should I look at?
Machine : i7 (4th generation - quad code with Hyper Threading) running windows 8 and Java 7.
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;
/*
* Purpose is to test system clock granularity
*/
public class ClockGranularity{
private static final int MaxExecutionTimeMsec = 6;
//60*1000 milliseconds
private static float delta = 0.01f;
//Inter-arrival Time(IAT): in milliseconds
static final int ArraySize =(int) ((float)MaxExecutionTimeMsec/delta);
private static final int convertMilliToNano = 1000000;
private static String getTime() {
DateFormat format = new SimpleDateFormat("dd-MMM-yy HH:mm:ss");
Calendar cal = Calendar.getInstance();
return format.format(cal.getTime());
}
/*
* Invoke 1 producer vs 1,2,3 consumers
* Write consumer to file
*/
public static void main(String args[]) {
ClockGranularity.delta = delta*convertMilliToNano;
long execStartTime = System.currentTimeMillis();
long experimentStartTime = System.nanoTime();
long execDuration, experimentRuntime;
Buffer requestQueue = new Buffer();
Producer producer = new Producer(requestQueue);
Consumer consumer = new Consumer(requestQueue);
Consumer consumer2 = new Consumer(requestQueue);
Consumer consumer3 = new Consumer(requestQueue);
consumer.start();
consumer2.start();
consumer3.start();
do {
execDuration = System.currentTimeMillis() - execStartTime;
experimentRuntime = System.nanoTime() - experimentStartTime;
if(experimentRuntime >= delta) {
experimentStartTime = System.nanoTime();
producer.run();
}
} while (execDuration <= MaxExecutionTimeMsec);
consumer.interrupt();
consumer2.interrupt();
consumer3.interrupt();
delta/=convertMilliToNano;
try {
String producerFile = "Producer-" + delta + " msec #" + getTime();
printToFile(producerFile,requestQueue.getQueue());
String consumerFile = "Consumer-" + delta + " msec#" + getTime();
printToFile(consumerFile, consumer.getValidateConsumerArray());
consumerFile = "Consumer2-" + delta + " msec#" + getTime();
printToFile(consumerFile, consumer2.getValidateConsumerArray());
consumerFile = "Consumer3-" + delta + " msec#" + getTime();
printToFile(consumerFile, consumer3.getValidateConsumerArray());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void printToFile(String outputFileName,Queue<Integer> requestQueue) throws IOException{
outputFileName = outputFileName.replace(':', '-');
String lineSeparator = System.lineSeparator();
File directory = new File("Practice Coding\\src\\ClockGranularity Test results\\Semaphore and Queue\\");
File file = File.createTempFile(outputFileName, ".txt",directory);
FileWriter writer = new FileWriter(file);
writer.append("Index \tQueue Contents" + lineSeparator);
int size = requestQueue.size();
String summary = "queue<>" + size;
for(int i = 0; i<size; i++) {
String temp = i + " ticks \t" + requestQueue.poll();
System.out.println(temp);
writer.append(temp + lineSeparator);
}
writer.append(lineSeparator + "Summary: " + lineSeparator);
writer.append(summary + lineSeparator);
System.out.println(outputFileName + " " + summary);
writer.close();
}
}
class Buffer {
private Queue<Integer> requestsQueue;
Semaphore accessQueue;
Buffer() {
requestsQueue = new LinkedList<Integer>();
accessQueue = new Semaphore(1);
}
public void put(Integer tick) throws InterruptedException {
accessQueue.acquire();
requestsQueue.add(tick);
accessQueue.release();
}
public synchronized int get() throws InterruptedException {
int tick;
while(requestsQueue.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
accessQueue.acquire();
tick = requestsQueue.poll();
accessQueue.release();
return tick;
}
public Queue<Integer> getQueue() {
return requestsQueue;
}
}
class Consumer extends Thread{
private Buffer bufferQueue;
private Queue<Integer> validateConsumer;
Consumer(Buffer requestQueue) {
bufferQueue = requestQueue;
validateConsumer = new LinkedList<Integer>();
}
public void run() {
while(true) {
int i;
try {
i = bufferQueue.get();
validateConsumer.add(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public Queue<Integer> getValidateConsumerArray() {
return validateConsumer;
}
}
class Producer extends Thread{
public int tick = 0;
private Buffer bufferQueue;
Producer(Buffer requestQueue) {
bufferQueue = requestQueue;
}
public void run() {
try {
bufferQueue.put(tick++);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Your Buffer implementation is wrong. It essentially serializes read/writes thus terrible performance. You need to use or implement a reader-writer lock instead.
Things you can do:
-Instead of doing busy loops (the query for time may be reducing your utilization), see if there is a difference if you put the producer code code to while(true) like you do with the consumers, sleep the main thread for MaxExecutionTimeMsec time, and do an interrupt on the producer like you do a consumer.
-This is backwards from its typically usage but run a special profiler and see how much time is spent where. If it isn't a business section (say waiting for lock acquisition) do a redesign there.
-You may want to look into spin-locks if performance is key and you have a multi-core p
processor. A context switch can be more expensive than a spin-lock in some amortized scenarios.

ExecutorService.submit(<callable>) taking more time?

I am trying to understand the utilities in java.util.concurrent package and learnt that we can submit callable objects to the ExecutorService, which returns Future, which is filled with the value returned by the callable, after successful completion of task within call() method.
I am understanding that all the callables are executed concurrently using multiple threads.
When I wanted to see how much improvement ExecutorService gives over the batch task execution, i thought of capturing time.
Following is the code which i tried to execute -
package concurrency;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorExample {
private static Callable<String> callable = new Callable<String>() {
#Override
public String call() throws Exception {
StringBuilder builder = new StringBuilder();
for(int i=0; i<5; i++) {
builder.append(i);
}
return builder.toString();
}
};
public static void main(String [] args) {
long start = System.currentTimeMillis();
ExecutorService service = Executors.newFixedThreadPool(5);
List<Future<String>> futures = new ArrayList<Future<String>>();
for(int i=0; i<5; i++) {
Future<String> value = service.submit(callable);
futures.add(value);
}
for(Future<String> f : futures) {
try {
System.out.println(f.isDone() + " " + f.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
System.out.println("Executer callable time - " + (end - start));
service.shutdown();
start = System.currentTimeMillis();
for(int i=0; i<5; i++) {
StringBuilder builder = new StringBuilder();
for(int j=0; j<5; j++) {
builder.append(j);
}
System.out.println(builder.toString());
}
end = System.currentTimeMillis();
System.out.println("Normal time - " + (end - start));
}
}
and here is the output of this -
true 01234
true 01234
true 01234
true 01234
true 01234
Executer callable time - 5
01234
01234
01234
01234
01234
Normal time - 0
Please let me know if I am missing something OR understanding something in a wrong way.
Thanks in advance for your time and help for this thread.
If you task in Callable is to small, you won't get benefits from concurrency due task switching and overhead for initialisation. Try to add more heavier loop in callable, say 1000000 iterations, and you can see difference
When you run any code esp for the first time, it takes time. If you pass a task to another thread it can take 1-10 micro-seconds and if your task take less time than this, the overhead can be greater than the benefit. i.e. using multiple threads can be much slower than using a single thread if your overhead is high enough.
I suggest you
increase the cost of the task to 1000 iterations.
make sure the result is not discarded in the single threaded example
run both tests for at least a couple of seconds to ensure the code has warmed up.
Not an answer (but I am not sure the code will fit a comment). To expand a bit on what Peter said, there is usually a sweet spot for the size of your jobs (measured in execution time), to balance pool/queue overhead with fair work distribution among workers. The code example helps find an estimate for that sweet spot. Run on your target hardware.
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class FibonacciFork extends RecursiveTask<Long> {
private static final long serialVersionUID = 1L;
public FibonacciFork( long n) {
super();
this.n = n;
}
static ForkJoinPool fjp = new ForkJoinPool( Runtime.getRuntime().availableProcessors());
static long fibonacci0( long n) {
if ( n < 2) {
return n;
}
return fibonacci0( n - 1) + fibonacci0( n - 2);
}
static int rekLimit = 8;
private static long stealCount;
long n;
private long forkCount;
private static AtomicLong forks = new AtomicLong( 0);
public static void main( String[] args) {
int n = 45;
long times[] = getSingleThreadNanos( n);
System.out.println( "Single Thread Times complete");
for ( int r = 2; r <= n; r++) {
runWithRecursionLimit( r, n, times[ r]);
}
}
private static long[] getSingleThreadNanos( int n) {
final long times[] = new long[ n + 1];
ExecutorService es = Executors.newFixedThreadPool( Math.max( 1, Runtime.getRuntime().availableProcessors() / 2));
for ( int i = 2; i <= n; i++) {
final int arg = i;
Runnable runner = new Runnable() {
#Override
public void run() {
long start = System.nanoTime();
final int minRuntime = 1000000000;
long runUntil = start + minRuntime;
long result = fibonacci0( arg);
long end = System.nanoTime();
int ntimes = Math.max( 1, ( int) ( minRuntime / ( end - start)));
if ( ntimes > 1) {
start = System.nanoTime();
for ( int i = 0; i < ntimes; i++) {
result = fibonacci0( arg);
}
end = System.nanoTime();
}
times[ arg] = ( end - start) / ntimes;
}
};
es.execute( runner);
}
es.shutdown();
try {
es.awaitTermination( 1, TimeUnit.HOURS);
} catch ( InterruptedException e) {
System.out.println( "Single Timeout");
}
return times;
}
private static void runWithRecursionLimit( int r, int arg, long singleThreadNanos) {
rekLimit = r;
long start = System.currentTimeMillis();
long result = fibonacci( arg);
long end = System.currentTimeMillis();
// Steals zählen
long currentSteals = fjp.getStealCount();
long newSteals = currentSteals - stealCount;
stealCount = currentSteals;
long forksCount = forks.getAndSet( 0);
System.out.println( "Fib(" + arg + ")=" + result + " in " + ( end-start) + "ms, recursion limit: " + r +
" at " + ( singleThreadNanos / 1e6) + "ms, steals: " + newSteals + " forks " + forksCount);
}
static long fibonacci( final long arg) {
FibonacciFork task = new FibonacciFork( arg);
long result = fjp.invoke( task);
forks.set( task.forkCount);
return result;
}
#Override
protected Long compute() {
if ( n <= rekLimit) {
return fibonacci0( n);
}
FibonacciFork ff1 = new FibonacciFork( n-1);
FibonacciFork ff2 = new FibonacciFork( n-2);
ff1.fork();
long r2 = ff2.compute();
long r1 = ff1.join();
forkCount = ff2.forkCount + ff1.forkCount + 1;
return r1 + r2;
}
}

Categories