I have some thread-related questions, assuming the following code. Please ignore the possible inefficiency of the code, I’m only interested in the thread part.
//code without thread use public static int getNextPrime(int from) { int nextPrime = from+1; boolean superPrime = false; while(!superPrime) { boolean prime = true; for(int i = 2;i < nextPrime;i++) { if(nextPrime % i == 0) { prime = false; } } if(prime) { superPrime = true; } else { nextPrime++; } } return nextPrime; } public static void main(String[] args) { int primeStart = 5; ArrayList list = new ArrayList(); for(int i = 0;i < 10000;i++) { list.add(primeStart); primeStart = getNextPrime(primeStart); } }
If I’m running the code like this and it takes about 56 seconds. If, however, I have the following code (as an alternative):
public class PrimeRunnable implements Runnable { private int from; private int lastPrime; public PrimeRunnable(int from) { this.from = from; } public boolean isPrime(int number) { for(int i = 2;i < from;i++) { if((number % i) == 0) { return false; } } lastPrime = number; return true; } public int getLastPrime() { return lastPrime; } public void run() { while(!isPrime(++from)) ; } } public static void main(String[] args) { int primeStart = 5; ArrayList list = new ArrayList(); for(int i = 0;i < 10000;i++) { PrimeRunnable pr = new PrimeRunnable(primeStart); Thread t = new Thread(pr); t.start(); t.join(); primeStart = pr.getLastPrime(); list.add(primeStart); } }
The whole operation takes about 7 seconds. I am almost certain that even though I only create one thread at a time, a thread doesn’t always finish when another is created. Is that right? I am also curious: why is the operation ending so fast?
When I’m joining a thread, do other threads keep running in the background, or is the joined thread the only one that’s running?
By putting the join() in the loop, you’re starting a thread, then waiting for that thread to stop before running the next one. I think you probably want something more like this:
By the way pr.getLastPrime() will return 0 in the case of no prime, so you might want to filter that out before adding it to your list. The PrimeRunnable has to absorb the work of adding to the final results list. Also, I think PrimeRunnable was actually broken by still having incrementing code in it. I think this is fixed, but I’m not actually compiling this.
Running 10000 threads in parallel is not a good idea. It’s a much better idea to create a reasonably sized fixed thread pool and have them pull work from a shared queue. Basically every worker pulls tasks from the same queue, works on them and saves the results somewhere. The closest port of this with Java 5+ is to use an ExecutorService backed by a thread pool. You could also use a CompletionService which combines an ExecutorService with a result queue.
An ExecutorService version would look like:
Hope that gave you some ideas. And I hope the last example seemed a lot better than the first.