Поместив join () в цикл, вы запускаете поток, затем ждете остановки этого потока перед запуском следующего. Я думаю, что вы, вероятно, хотите что-то вроде этого:
public static void main(String[] args) {
int primeStart = 5;
// Make thread-safe list for adding results to
List list = Collections.synchronizedList(new ArrayList());
// Pull thread pool count out into a value so you can easily change it
int threadCount = 10000;
Thread[] threads = new Thread[threadCount];
// Start all threads
for(int i = 0;i < threadCount;i++) {
// Pass list to each Runnable here
// Also, I added +i here as I think the intention is
// to test 10000 possible numbers>5 for primeness -
// was testing 5 in all loops
PrimeRunnable pr = new PrimeRunnable(primeStart+i, list);
Thread[i] threads = new Thread(pr);
threads[i].start(); // thread is now running in parallel
}
// All threads now running in parallel
// Then wait for all threads to complete
for(int i=0; i<threadCount; i++) {
threads[i].join();
}
}
Кстати, pr.getLastPrime () вернет 0 в случае отсутствия простого числа, так что вы можете отфильтровать это перед добавлением в свой список. PrimeRunnable должен поглощать работу по добавлению в список окончательных результатов. Кроме того, я думаю, что PrimeRunnable был на самом деле сломан из-за увеличения кода. Я думаю, что это исправлено, но на самом деле я не собираю это.
public class PrimeRunnable implements Runnable {
private int from;
private List results; // shared but thread-safe
public PrimeRunnable(int from, List results) {
this.from = from;
this.results = results;
}
public void isPrime(int number) {
for(int i = 2;i < from;i++) {
if((number % i) == 0) {
return;
}
}
// found prime, add to shared results
this.results.add(number);
}
public void run() {
isPrime(from); // don't increment, just check one number
}
}
Запуск 10000 потоков параллельно - не очень хорошая идея. Намного лучше создать пул с фиксированными потоками разумного размера и заставить их извлекать работу из общей очереди. По сути, каждый работник извлекает задачи из одной и той же очереди, работает над ними и сохраняет результаты где-то. Ближайший порт этого в Java 5+ - это использование ExecutorService, поддерживаемого пулом потоков. Вы также можете использовать CompletionService, который объединяет ExecutorService с очередью результатов.
Версия ExecutorService будет выглядеть так:
public static void main(String[] args) {
int primeStart = 5;
// Make thread-safe list for adding results to
List list = Collections.synchronizedList(new ArrayList());
int threadCount = 16; // Experiment with this to find best on your machine
ExecutorService exec = Executors.newFixedThreadPool(threadCount);
int workCount = 10000; // See how # of work is now separate from # of threads?
for(int i = 0;i < workCount;i++) {
// submit work to the svc for execution across the thread pool
exec.execute(new PrimeRunnable(primeStart+i, list));
}
// Wait for all tasks to be done or timeout to go off
exec.awaitTermination(1, TimeUnit.DAYS);
}
Надеюсь, это дало вам некоторые идеи. И я надеюсь, что последний пример казался намного лучше, чем первый.