Currently my code instantiates a class for a number of cores one after the other but I would like to create a loop that instantiates the class detectors() for an arbitrary number of cores, running concurrently.
int processors = Runtime.getRuntime().availableProcessors(); // finds the number of available threads
detectors.getStartingConditions();
long startTime = System.currentTimeMillis();
detectors core1= new detectors();
detectors core2= new detectors();
detectors core3= new detectors();
//etc
core1.start();
core2.start();
core3.start();
//etc
try
{ // wait for completion of all thread and then sum
core1.join();
core2.join();
core3.join();
//etc
}
catch(InterruptedException IntExp) {}
long endTime = System.currentTimeMillis();
System.out.println("That took " + (endTime - startTime) + " milliseconds");
My attempt at a solution:
I created a array of objects as follows but the processor cores run one after the other as opposed to concurrently.
edit: the cores now run concurrently.
int processors = Runtime.getRuntime().availableProcessors(); // finds the number of available threads
detectors[] theCores = new detectors[processors];
detectors.getStartingConditions();
long startTime = System.currentTimeMillis();
for(int i = 0; i <= processors-1; i++){
theCores[i] = new detectors();
theCores[i].start();
}
for(int i = 0; i <= processors-1; i++){
try{
theCores[i].join();}
catch(InterruptedException IntExp) {}
}
long endTime = System.currentTimeMillis();
System.out.println("That took " + (endTime - startTime) + " milliseconds");
Your code creates threads and joins it before creating the next thread. That causes the sequential execution. You have to use two loops instead. The first loop creates all threads, whereas the second loop joins all threads.
for (int i = 0; i < processors; ++i) {
theCores[i] = new detectors();
theCores[i].start();
}
for (int i = 0; i < processors; ++i) {
try {
theCores[i].join();
} catch (InterruptedException ie) {
RuntimeException re = new RuntimeException("unsupported interruption", ie);
for (++i; i < processors; ++i) {
try {
theCores[i].join();
} catch (InterruptedException e) {
re.addSuppressed(e);
}
}
throw re;
}
}
Related
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());
Here is a main that runs a simple counting loop three ways:
Single-threaded
2 threads using inline code that creates two distinct Thread objects
2 threads using instances of the CountingThread class that inherits from Thread
package main;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
demo();
}
public static void demo() {
final long limit = 100_000_000_000L;
long startTime = System.currenatTimeMillis();
for (long i = 0; i < limit; i++) {
// Nothing to see here, just counting
}
long endTime = System.currentTimeMillis();
System.out.println("Single threaded: Total execution time: " + (endTime - startTime) + " milliseconds.");
// Now try it in two threads. Each thread will perform 1/2 of the counting
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
for (long i = 0; i < limit/2; i++) {
// Nothing to see here, just counting
}
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
for (long i = limit/2; i < limit; i++) {
// Nothing to see here, just counting
}
}
});
startTime = System.currentTimeMillis();
t1.start();
t2.start();
// Join t1 until it ends, then join t2 until it ends. Note that t1 and t2 are running in parallel with this thread.
try {t1.join();} catch (InterruptedException e) {}
try {t2.join();} catch (InterruptedException e) {}
endTime = System.currentTimeMillis();
System.out.println("2 threaded using inline code: Total execution time: " + (endTime - startTime) + " milliseconds.");
// Now try it with 2 instances of the CountingThread class.
ArrayList<CountingThread> countingThreads = new ArrayList<CountingThread>();
int numberOfThreads = 2;
long increment = limit / numberOfThreads;
for (int i = 0; i < numberOfThreads; i++) {
long start, end;
start = i * increment;
end = start + increment;
countingThreads.add(new CountingThread(start, end));
}
// Launch all the threads to run in parallel
startTime = System.currentTimeMillis();
for (int i = 0; i < numberOfThreads; i++) {
countingThreads.get(i).run();
}
// Wait for all the threads to finish
for (int i = 0; i < numberOfThreads; i++) {
try {countingThreads.get(i).join();} catch(InterruptedException ex) {}
}
endTime = System.currentTimeMillis();
System.out.println(numberOfThreads + " threaded using classes: Total execution time: " + (endTime - startTime) + " milliseconds.");
}
}
Here is the class that inherits from Thread:
package main;
/**
* Count from one long int up to another long int. Really simple
*
*/
public class CountingThread extends Thread {
private long start, end;
public CountingThread(long start, long end) {
this.start = start;
this.end = end;
}
#Override
public void run() {
for(long i = start; i <= end; i++) {
}
// System.out.println("Thread counted from " + start + " to " + end);
}
}
Here is the output:
Single threaded: Total execution time: 40379 milliseconds.
2 threaded using inline code: Total execution time: 23312 milliseconds.
2 threaded using classes: Total execution time: 40358 milliseconds.
It seems like methods 2 and 3 should take about the same amount of time. What's up with that?
The machine has 4 cores.
You made a mistake and call #run instead of #start. Run method is executed in the same thread.
countingThreads.get(i).run();
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");
I have a quad core cpu, and I've been trying to experiment with multithreading for performance reasons. I've written this code below just to see how fast it would go, and I noticed that it's actually slower than the 2nd code block that only uses the main thread
int numCrunchers = Runtime.getRuntime().availableProcessors();
public void crunch() {
int numPairs = 1000;
for(int i=0; i < numPairs; i++)
pairs.add(...);
int share = pairs.size()/numCrunchers;
for(int i=0; i < numCrunchers; i++) {
Cruncher cruncher = crunchers.get(i);
for(int j=0; j < share; j++)
cruncher.nodes.add(pairs.poll());
}
for(Cruncher cruncher : crunchers)
threadpool.execute(cruncher);
threadpool.shutdown();
try {
threadpool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class Cruncher implements Runnable {
public BlockingQueue<Pair<PathNode>> nodes = new LinkedBlockingQueue<Pair<PathNode>>();
private AStarPathfinder pathfinder;
private LinkedList<PathNode> path = new LinkedList<PathNode>();
public Cruncher(GridGraph graph) {
pathfinder = new AStarPathfinder(graph);
}
#Override
public void run() {
while(true) {
path.clear();
Pair<PathNode> pair = nodes.poll();
if(pair != null) {
pathfinder.search(path, pair.first(), pair.second());
paths.add(new LinkedList<PathNode>(path));
} else {
System.out.println("This cruncher is done");
break;
}
}
}
}
Each thread took around 34,000,000,000 nanoseconds on my pc, but when I decided to use no threads except for the main thread, it only took 1,090,195,046 nanoseconds, 34x time difference.
LinkedList<Pair<PathNode>> pairs = new LinkedList<Pair<PathNode>>();
int numPairs = 1000;
AStarPathfinder pathfinder = new AStarPathfinder(graph);
for(int i=0; i < numPairs; i++)
pairs.add(...);
long current = System.nanoTime();
for(int i=0; i < numPairs; i++) {
Pair<PathNode> pair = pairs.poll();
path.clear();
pathfinder.search(path, pair.first(), pair.second());
}
System.out.printf("Operation took %d nanoseconds", System.nanoTime() - current);
My question is why using multiple threads causes my program to run slow? Is the code not properly taking advantage of all the cores on my cpu? I ran this several times, and the results were similar, (30+)x time difference between multithreading and single-threading
Edit:
Decided to measure the time of each individual operation on the multithreaded
while(true) {
path.clear();
Pair<PathNode> pair = nodes.poll();
if(pair != null) {
long current = System.nanoTime();
pathfinder.search(path, pair.first(), pair.second());
paths.add(new LinkedList<PathNode>(path));
System.out.printf("Took %d nanoseconds\n", System.nanoTime() - current);
} else {
System.out.println("This cruncher is done");
break;
}
}
and single threaded...
LinkedList<Pair<PathNode>> pairs = new LinkedList<Pair<PathNode>>();
int numPairs = 1000;
AStarPathfinder pathfinder = new AStarPathfinder(graph);
for(int i=0; i < numPairs; i++)
pairs.add(...);
for(int i=0; i < numPairs; i++) {
long current = System.nanoTime();
Pair<PathNode> pair = pairs.poll();
path.clear();
pathfinder.search(path, pair.first(), pair.second());
System.out.printf("Operation took %d nanoseconds", System.nanoTime() - current);
}
Each Cruncher has its own AStarPathfinder instance, so the pathfinder.search() couldn't be causing blocking between each of the threads. The multithreaded application was still much slower.
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;
}
}