多线程 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++;
}
}
目前我正在尝试使用 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++;
}
}