多线程 Prime 查找器 Java

Multithreaded Prime finder Java

目前我正在尝试使用 java 中的线程实现素数查找器。不幸的是,它似乎没有按照我预期的方式工作。

我基本上想要的是我有一个 while(true) 循环来无限期地生成数字。生成数字后,线程应获取该数字并检查它是否为素数。当第一个线程仍在检查素数时,第二个线程已经抓取下一个数字来检查素数,依此类推。

现在数字生成确实有效,但所有线程似乎都使用相同的数字,这对我的实现没有意义。

这是我项目的当前状态:

public class Main {
    public static void main(String[] args) {
        int logicalCores = Runtime.getRuntime().availableProcessors();
        int startFrom = 0;
        startCalc(logicalCores, startFrom);
    }

    public static void startCalc(int threadCount, int startFrom){
        for (int i = 0; i < threadCount; i++ ){
            PrimeCalculator calculator = new PrimeCalculator(startFrom, i);
            Thread thread = new Thread(calculator);
            thread.start();
        }    
    }
}

import static java.lang.Thread.sleep;

public class PrimeCalculator implements Runnable{    
    int startingCounter;
    int id;
    public PrimeCalculator(int counter, int id){
    this.startingCounter = counter;
    this.id = id;
    }

    @Override
    public void run() {
        Integer counter = startingCounter;

        while(true){                
            if (isPrime((counter))){
                System.out.printf("Thread with ID %d found that %d is a prime! \n", id, counter );

                try{
                    sleep(10000);
                } catch (Exception e){    
                }    
            }

            synchronized (counter){
                counter++;
            }
        }
    }

    public static boolean isPrime(int n)
    {
        if (n == 2 || n == 3 || n == 5) return true;
        if (n <= 1 || (n&1) == 0) return false;
        for (int i = 3; i*i <= n; i += 2)
            if (n % i == 0) return false;
        return true;
    }    
}

问题是所有线程似乎都在检查同一个数字。例如,数字是 2,但我的 CPU 的所有 16 个线程都检查素数,而实际上像 Thread0 这样的线程应该检查数字 2 是否为素数,而其他线程已经在检查计数器的增量(例如 Thread15 已经在16) 等等

编辑:

我想我需要给出一个更好的预期行为示例。

假设我有一台 4 核 4 线程的计算机。这将使我的主要方法中的 logicalCores 变量成为 4,并在函数“startCalc”中创建 4 个线程。

现在循环应该从定义的起点生成数字。假设点为 0。 现在应该发生的是一个线程,我们就称它为 thread0 正在获取那个数字并检查它是否是素数。与此同时,循环产生了计数器的增量,现在位于“1”。现在,因为 thread0 仍在检查 0 是否为质数,第二个线程 thread1 获取了值为“1”的当前计数器并正在检查“1”是否为质数。

这里的目标是每个线程都以防止重复检查的方式检查素数。例如(我们不希望 thread0 检查 1 是否为素数,因为 thread1 已经检查过了)

您的计数器应该是所有线程共享的值,以便从一个线程递增它会影响所有并发线程。

最简单的方法是使用 static 字段。然后使用某种同步来避免线程同时递增/读取计数器。

public class Main {
  public static void main(String[] args) {
    int logicalCores = Runtime.getRuntime().availableProcessors();
    int startFrom = 0;
    startCalc(logicalCores, startFrom);
  }

  public static void startCalc(int threadCount, int startFrom) {
    PrimeCalculator.startAt(startFrom); //Set this for all threads
    for (int i = 0; i < threadCount; i++) {
      PrimeCalculator calculator = new PrimeCalculator(i);
      Thread thread = new Thread(calculator);
      thread.start();
    }
  }
}
import static java.lang.Thread.sleep;

public class PrimeCalculator implements Runnable {

  static int counter; //Use static variable
  int id;

  public static void startAt(int counterStart) { //Set start once for all threads
    counter = counterStart;
  }

  public PrimeCalculator(int id) {
    this.id = id;
  }

  @Override
  public void run() {
    while (true) {
      int current = incrementAndGetCounter();

      if (isPrime((current))) {
        System.out.printf("Thread with ID %d found that %d is a prime! \n", id, current);

        try {
          sleep(1000);
        } catch (Exception e) {
        }
      }
    }
  }

  public static boolean isPrime(int n) {
    if (n == 2 || n == 3 || n == 5)
      return true;
    if (n <= 1 || (n & 1) == 0)
      return false;
    for (int i = 3; i * i <= n; i += 2)
      if (n % i == 0)
        return false;
    return true;
  }

  //Use synchronized method to increment and get value
  //to prevent one thread incrementing it while another one is reading it
  private static synchronized int incrementAndGetCounter() {
    return counter++;
  }
}