How to use multithreading in a loop in Java - java

Here's what I'm trying to do. I am recording data from different sensors in a while loop until the user stops the recording. I want to record as much data as possible per second. The sensors require different time to return a value, between 200ms and 3 seconds. Therefore, sequentially calling the sensors successively is not an option.
Sequentially calling the sensors looks like this:
List<DataRow> dataRows= new ArrayList<DataRow>();
while (recording) {
DataRow dataRow = new DataRow();
dataRow.setDataA(sensorA.readData());
dataRow.setDataB(sensorB.readData());
dataRow.setDataC(sensorC.readData());
dataRows.add(dataRow);
}
Depending on the sensor, reading the data looks (much simplified) like that
public class SensorA {
public SensorAData readData(){
sensorA.startSensing();
try {
TimeUnit.MILLISECONDS.sleep(750);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return sensorA.readAndConvertByteStream();
}
}
To utilize Multithreading can SensorA implement Callable and receive Future objects in the loop? Or should the while loop be placed within a run() method implementing the interface Runnable?
Basically, can Java (or a thread) write to the correct dataRow object even if the loop is already at least one iteration further? If not, how can one solve this problem?

If I understand your needs correctly, this may be solution you want:
In each iteration n sensors are read by n concurrent threads,
If all threads has sensors data collected, new result row is added to list
Working code:
public class TestX {
private final ExecutorService pool = Executors.newFixedThreadPool(3);
private final int N = 10;
// all sensors are read sequentially and put in one row
public void testSequential() {
int total = 0;
long t = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
System.out.println("starting iteration " + i);
int v1 = getSensorA(); // run in main thread
int v2 = getSensorB(); // run in main thread
int v3 = getSensorC(); // run in main thread
// collection.add( record(v1, v2, v3)
total += v1 + v2 + v3;
}
System.out.println("total = " + total + " time = " + (System.currentTimeMillis() - t) + " ms");
}
// all sensors are read concurrently and then put in one row
public void testParallel() throws ExecutionException, InterruptedException {
int total = 0;
long t = System.currentTimeMillis();
final SensorCallable s1 = new SensorCallable(1);
final SensorCallable s2 = new SensorCallable(3);
final SensorCallable s3 = new SensorCallable(3);
for (int i = 0; i < N; i++) {
System.out.println("starting iteration " + i);
Future<Integer> future1 = pool.submit(s1); // run in thread 1
Future<Integer> future2 = pool.submit(s2); // run in thread 2
Future<Integer> future3 = pool.submit(s3); // run in thread 3
int v1 = future1.get();
int v2 = future2.get();
int v3 = future3.get();
// collection.add( record(v1, v2, v3)
total += v1 + v2 + v3;
}
System.out.println("total = " + total + " time = " + (System.currentTimeMillis() - t) + " ms");
}
private class SensorCallable implements Callable<Integer> {
private final int sensorId;
private SensorCallable(int sensorId) {
this.sensorId = sensorId;
}
#Override
public Integer call() throws Exception {
switch (sensorId) {
case 1: return getSensorA();
case 2: return getSensorB();
case 3: return getSensorC();
default:
throw new IllegalArgumentException("Unknown sensor id: " + sensorId);
}
}
}
private int getSensorA() {
sleep(700);
return 1;
}
private int getSensorB() {
sleep(500);
return 2;
}
private int getSensorC() {
sleep(900);
return 2;
}
private void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
// ignore
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
new TestX().testSequential();
new TestX().testParallel();
}
}
and output:
starting iteration 0
starting iteration 1
starting iteration 2
starting iteration 3
starting iteration 4
starting iteration 5
starting iteration 6
starting iteration 7
starting iteration 8
starting iteration 9
total = 50 time = 21014 ms
starting iteration 0
starting iteration 1
starting iteration 2
starting iteration 3
starting iteration 4
starting iteration 5
starting iteration 6
starting iteration 7
starting iteration 8
starting iteration 9
total = 50 time = 9009 ms
-- EDIT --
in java 8 you can use method reference to get rid of Callable classes and just write:
Future<Integer> future1 = pool.submit( this::getSensorA() );
Future<Integer> future2 = pool.submit( this::getSensorB() );
Future<Integer> future3 = pool.submit( this::getSensorC() );

Related

Java: Volatile variable not updating (get and set methods not working)

I have a Runnable "NanoClock" class which keeps updating a private volatile double value in its run() method.
This class also has a getTime() method which returns the double value. Another class ("Master") is constructing the NanoClock class and creates a thread, as well as calling the start() method.
After it did this it calls the getTime() method several times (with a delay), but the value is not updating. What am I doing wrong?
NanoClock.java :
public class NanoClock implements Runnable {
private volatile boolean running;
private volatile double time;
public NanoClock() {
time = System.currentTimeMillis();
}
#Override
public void run() {
running = true;
while(running) {
try {
if(System.currentTimeMillis() > time) {
time = System.currentTimeMillis();
}
//This returns the updated value continuously when commented out
//System.out.println("Time: " + String.format("%.6f", unix_time));
Thread.sleep(2000);
} catch(Exception exc) {
exc.printStackTrace();
System.exit(1);
}
}
}
public double getTime() {
return time;
}
public void end() {
running = false;
}
}
Master.java:
public class Master {
public static void main(String[] args) {
try {
NanoClock nClock = new NanoClock();
Thread clockThread = new Thread(new NanoClock());
clockThread.setPriority(10);
clockThread.start();
//MY_ISSUE: This returns the same value every time
for(int a = 0; a < 10; a++) {
System.out.println("Time: " + nClock.getTime());
}
//MY_ISSUE: This cannot stop the while loop - I tested it with
//the println in the NanoClock class.
nClock.end();
System.out.println("Done!");
catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
You've got two instances of NanoClock: one of them is an anonymous new NanoClock() which, as the Runnable in your other thread is happily keeping time in the backgound; the other is nClock, which is sitting idly by in the foreground in your main thread.
nClock should have been the Runnable in that other thread:
Thread clockThread = new Thread(nClock); // not new NanoClock()
This may not be the entire solution, but it should be a big step in the right direction.
System.currentTimeMillis() returns a long, but you store it in a double, which causes a loss of precision. When you change the member time (and also the return type of its getter) to a long you should get the expected result.
As a rule of thumb: When working with time units long is most appropriate datatype most of the time. Floating point numbers are not suitable to store precise results.
Thread.sleep(2000);
System.out.println("Time: " + nClock.getTime());
the for in main() must be sleep(2000)
If the code below will take 2 seconds, then the time will change.
//MY_ISSUE: This returns the same value every time
for(int a = 0; a < 10; a++) {
System.out.println("Time: " + nClock.getTime());
}
However a for loop with 10 iterations and a system.out will not even take a millisecond so it will not change.
Why 2 seconds? because you have a Thread.sleep in your runnable code.
Thread.sleep(2000);
Which means, the next update will be in 2 seconds.
And use System.nanoTime() instead of System.currentTimeMillis() since you really wanted nano time not millis.
Updated:
In my machine
public static void main(String args[]) {
long start = System.currentTimeMillis();
for(int a = 0; a < 10; a++) {
System.out.println("Iterating " + a);
}
long end = System.currentTimeMillis();
System.out.println("Start = " + start);
System.out.println("End = " + end);
}
Result, there is no difference in the start time and end time
Iterating 0
Iterating 1
Iterating 2
Iterating 3
Iterating 4
Iterating 5
Iterating 6
Iterating 7
Iterating 8
Iterating 9
Start = 1499592836298
End = 1499592836298
That code block executed so fast that it did not take even a single millisecond. Depending on the timing, it may take 1 millisecond.
Changing it to System.nanoTime()
public static void main(String args[]) {
long start = System.nanoTime();
for(int a = 0; a < 10; a++) {
System.out.println("Iterating " + a);
}
long end = System.nanoTime();
System.out.println("Start = " + start);
System.out.println("End = " + end);
}
Result, there is a difference in the start time and end time.
Iterating 0
Iterating 1
Iterating 2
Iterating 3
Iterating 4
Iterating 5
Iterating 6
Iterating 7
Iterating 8
Iterating 9
Start = 1012518090518837
End = 1012518091012960

start multiple threads at the same time

For our assignment for class, we have to count the amount of words in a txt file by splitting it into n segments, which we are supposed to be able to set before launching the programm. Each segment should then get its own thread, which counts the words and then stops. At the end, the main thread should collect all the individual word counts and add them together.
This is (part of) what I wrote so far
for (int i = 0; i < segments; i++){
Thread thread = new Thread();
thread.start();
int words = counting(stringarray[i]);
totalwords += words;
long nanos = ManagementFactory.getThreadMXBean().getThreadCpuTime(Thread.currentThread().getId());
System.out.println("This Thread read " + words + " words. The total word count now is " + totalwords +
". The time it took to finish for this thread is " + nanos +".");
System.out.println("Number of active threads from the given thread: " + Thread.activeCount());
}
Now, while this gets the primary job done (counting the words in different threads and adding them to the total), I dont know how to just "leave the thread be" and then add the individual wordcounts together after every thread has done its job.
Additionally, while this is definitely starting multiple threads, it only ever prints out that I have 2, or maybe 3 threads running at a time, even if I split the txt into 100 segments. Is there a way to have them all run at the same time?
The wording of the question suggest that each thread has its own counter, so I would declare a thread class:
public class WordCounter extends Thread {
private String text;
private int count;
public WordCounter(String text) {
this.text = text;
}
public int getCount() {
return count;
}
#Override
public void run() {
count = counting(text);
}
}
and use it as follows:
WordCounter[] threads = new WordCounter[segments];
for (int i = 0; i < segments; ++i) {
threads[i] = new WordCounter(stringarray[i]);
threads[i].start();
}
int total = 0;
for (int i = 0; i < segments; ++i) {
threads[i].join();
total += threads[i].getCount();
}
You may use next code snippet as a basis.
Note, that in case you increment common variable in different threads, this operation has to be thread-safe. That's why AtomicInteger variable is used as a counter
final List<String> segments = new ArrayList<>();
//TODO:Fill segments ... this is up to you
//In case threads will increment same variable it has to be thread-safe
final AtomicInteger worldCount = new AtomicInteger();
//Create Thread for each segment (this is definitely not optimal)
List<Thread> workers = new ArrayList<>(segments.size());
for (int i = 0; i < segments.size(); i++) {
final String segment = segments.get(i);
Thread worker = new Thread(new Runnable() {
#Override
public void run() {
//increment worldCount
worldCount.addAndGet(counting(segment));
}
});
workers.add(worker);
worker.start();
}
//Wait until all Threads are finished
for (Thread worker : workers) {
worker.join();
}
int result = worldCount.get();
Same solutions, but with Executors:
final List<String> segments = new ArrayList<>();
segments.add("seg1");
segments.add("seg2");
segments.add("seg 3");
final AtomicInteger worldCount = new AtomicInteger();
List<Future> workers = new ArrayList<>(segments.size());
ExecutorService executor = Executors.newFixedThreadPool(segments.size());
for (String segment : segments) {
Future<Integer> worker = executor.submit(() -> worldCount.addAndGet(counting(segment)));
workers.add(worker);
}
executor.shutdown();
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
System.out.println("Still waiting...");
System.exit(0);
}
int result = worldCount.get();
System.out.println("result = " + result);

Grid Search better performance using threads

I am working on a classification problem and I have implemented a grid search algorithm in order to find the best accuracy. My problem is that the program's execution time is about 2 hours and I have tried to improve this time by using threads. Obviously something I'm doing wrong since the execution time was the same even after implementing the threads. Bellow is the algorithm.
I must specify that is the first time I am using threads, I have read some good things about Executors, but I can't figure out how to implement them.
public static void gridSearch(Dataset ds)
{
double bestAcc = 0;
for (int i = -5; i < 15; i++) {
double param1 = Math.pow(2, i);
for (int j = -15; j < 3; j++) {
double param2 = Math.pow(2, j);
int size = 10;
CrossValidation[] works = new CrossValidation[size];
Thread[] threads = new Thread[size];
for (int k=1;k<=size;k++) {
CrossValidation po = new CrossValidation(param1, param2, ds);;
works[k-1] = po;
Thread t = new Thread(po);
threads[k-1] = t;
t.start();
}
for (int k = 0; k < size; k++) {
try { threads[k].join(); } catch (InterruptedException ex) {}
double accuracy = works[k].getAccuracy();
accuracy /= 106;
if (accuracy > bestAccuracy)
bestAcc = accuracy;
}
}
}
System.out.println("Best accuracy: " + bestAcc);
}
The CrossValidation class implements Runnable and has a method getAccuracy that returns the accuracy.
Please help me figure it out what I am doing wrong, in order to improve the execution time.
Your problem seems to be that you start for each parameter setting 10 threads instead of starting a thread for each parameter setting. Look closely what you're doing here. You're generating param1 and param2 and then start 10 threads that work with those parameters - redundantly. After that you are waiting for those threads to finish before you start over again.
But no worries, I have prepared something for you ...
I want to show you how you could make a Thread Pool do what you actually want to achieve here. It will be easier to understand once you get it running and note that:
You can download the whole example here.
First you need a WorkerThread and something like CVResult to return the results. This is where you are going to perform the CrossValidation algorithm:
public static class CVResult {
public double param1;
public double param2;
public double accuracy;
}
public static class WorkerThread implements Runnable {
private double param1;
private double param2;
private double accuracy;
public WorkerThread(double param1, double param2){
this.param1 = param1;
this.param2 = param2;
}
#Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" [parameter1] " + param1 + " [parameter2]: " + param2);
processCommand();
}
private void processCommand() {
try {
Thread.sleep(500);
;
/*
* ### PERFORM YOUR CROSSVALIDATION ALGORITHM HERE ###
*/
this.accuracy = this.param1 + this.param2;
// Give back result:
CVResult result = new CVResult();
result.accuracy = this.accuracy;
result.param1 = this.param1;
result.param2 = this.param2;
Main.addResult(result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
You also need to assure you have access to a ExecutorService and List<Future>. ExecutorService will take care of your threads and we will initialize the number of threads to be the number of cores that your CPU has available. This will ensure that no more threads are running than cores are available on your CPU - however - no task gets lost because each thread gets enqueued and starts after another has finished. You'll see that soon. List<Future> will allow us to wait for all threads to finish before we continue with the main thread. List<CVResult> is of course there to hold the results added by the threads (note that it is synchronized since multiple threads are going to access it).
private static ExecutorService executor = null;
private static List<Future> futures = new ArrayList<>();
private static List<CVResult> resultList = Collections.synchronizedList(new ArrayList<CVResult>());
This is how your gridSearch() would look like. You don't have to initialize executor here.. you can do that wherever you want of course:
public static void gridSearch(/*Dataset ds*/)
{
double bestAcc = 0;
int cores = Runtime.getRuntime().availableProcessors();
executor = Executors.newFixedThreadPool(cores);
for (int i = -5; i < 15; i++) {
double param1 = Math.pow(2, i);
for (int j = -15; j < 3; j++) {
double param2 = Math.pow(2, j);
Runnable worker = new WorkerThread(param1, param2);
futures.add(executor.submit(worker));
}
}
System.out.println("Waiting for all threads to terminate ..");
// Joining all threads in order to wait for all to finish
// before returning from gridSearch()
for (Future future: futures) {
try {
future.get(100, TimeUnit.SECONDS);
} catch (Throwable cause) {
// process cause
}
}
System.out.println("Printing results ..");
for(CVResult result : resultList) {
System.out.println("Acc: " + result.accuracy +
" for param1: " + result.param1 +
" | param2: " + result.param2);
}
}
Last but not least here is a synchronized method to add your results to the list:
public static void addResult(CVResult accuracy) {
synchronized( resultList ) {
resultList.add(accuracy);
}
}
If you call this in your main e.g. like this:
public static void main(String[] args) {
gridSearch(/* params */);
System.out.println("All done.");
}
You'll get an output like this:
...
pool-1-thread-5 [parameter1] 0.0625 [parameter2]: 3.0517578125E-5
param1 0.03125
param2 1.0
pool-1-thread-4 [parameter1] 0.0625 [parameter2]: 0.25
param1 0.0625
param2 0.03125
...
Printing results ..
...
Acc: 16384.5 for param1: 16384.0 | param2: 0.5
Acc: 16386.0 for param1: 16384.0 | param2: 2.0
...
All done.
Possibly because thread creation/teardown overhead is increasing the time needed to run the threads, fix this by using Executors. This will help you get started. As commented already, your processor may also not have the available processing threads or physical cores to execute your threads concurrently.
More prominently, between each of the -15 to 3 iterations, you must wait. To fix this, move your waiting and processing to the end of the for loop, once everything is processed. That way, the last 10 threads do not need to completely before starting the next batch. Additionally, I recommend using a CountDownLatch to await full completion before processing the results.

Java [threads] - summarizing table with multiple threads doesn't seem to work

I am learning java, and trying to summarize elements in table with multiple threads, but I am always getting wrong result.
I tried 4 different methods of threads synchronization and all of them failed. Everything is explained in the comments.
My result (bad):
Without threads: 4949937, 15ms
With threads: 4944805, 78ms
Maybe am I executing the System.out.println on summarizeT() too early? I mean before all the threads finish work. With .join() the summarizeT() method works good but. Is the .join() blocking the "main" thread until all other threads are finished?
Main class:
public class Main
{
static int size = 100000; //size of tab
static int length = 100; //each thread gets 100 elements of tab, thread 1 calculates sum from 0 to 99, thread 2 from 100 to 199 etc.
static int[] tab = new int[size];
static Random generator = new Random();
static void initialize()
{
for (int i = 0; i < size; i++)
tab[i] = generator.nextInt(100);
}
static int summarize() //summarize with only one thread
{
int sum = 0;
for (int i = 0; i < size; i++)
sum += tab[i];
return sum;
}
static int summarizeT() //summarize with more threads (size / length)
{
int threadsCounter = size/length;
int start = 0; //pointer to table from where each thread should start counting
int[] sum = new int[1]; //I am sharing the sum value between threads with table, not sure if it is best method to pass the value between them
sum[0] = 0;
Thread[] threads = new Thread[threadsCounter]; //nedeed for .join() test
for (int i = 0; i < threadsCounter; i++)
{
threads[i] = new Thread(new MyThread(tab, start, sum));
threads[i].start();
start += length; //moving the start pointer, next thread should start counting from next 100 indexes
}
/*for (int i = 0; i < threadsCounter; i++) // adding .join() solves the problem, but is it a good solution?
{
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
return sum[0];
}
public static void main(String[] args)
{
initialize();
long start = Calendar.getInstance().getTimeInMillis();
System.out.println("Without threads: " + summarize() + ", " + (Calendar.getInstance().getTimeInMillis() - start) + "ms");
start = Calendar.getInstance().getTimeInMillis();
System.out.println("With threads: " + summarizeT() + ", " + (Calendar.getInstance().getTimeInMillis() - start) + "ms"); //giving wrong answer
}
}
MyThread class:
import java.util.concurrent.Semaphore;
public class MyThread extends Thread
{
int[] tab;
int[] sum;
int start;
MyThread(int tab[], int start, int sum[]) //in args: main table, starting index, value that is being shared between threads
{
this.tab = tab;
this.start = start;
this.sum = sum;
}
#Override
public void run()
{
int end = start + Main.length; //place where thread should stop counting
int temp = 0; //nedeed to sumarize the "subtable"
while (start < end)
{
temp += tab[start];
start++;
}
// Method 1
Semaphore semaphore = new Semaphore(1);
try {
semaphore.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try
{
sum[0] += temp;
} catch (Exception e) {
} finally {
semaphore.release();
}
// Method 2
/*Object lock = new Object();
synchronized(lock)
{
sum[0] += temp;
}*/
// Method 3
/*synchronized(this)
{
sum[0] += temp;
}*/
// Method 4
//summarize(temp);
// Method 5 - no threads synchronization, works only when .join() is used, the same as other methods
//sum[0] += temp;
}
private synchronized void summarize(int value)
{
sum[0] += value;
}
}
Isn't the problem here that you create a lock object , or semaphore object, in each thread, rather than having one object that all threads synchronise on?
Each Thread creates is own Semaphore object ( for example ) so no other thread will ever contend with it. You need to create an object that ALL threads have access to and synchronise on that. You might consider synchronising on the array that you are writing the results in to itself.
There are some problems with your solution.
You should use AtomicInteger to hold results. that way you don't need to synchronize sum update.
BTW the way you synchronize is invalid. For semaphores to work you need to share same instance between all threads. And your try/catch/finally blocks are invalid. You should do acquire() and sum update in one try block, and release() in it's finally. That way you did it. It is possible that you'll do sum update even though acquire() failed.
Also you return from summarizeT() without waiting for threads to finish. You have to implement thread.join() logic or some other way to wait.

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