1

所以正如标题所示,我试图找到从 0 到 MAX_LIMIT 的所有素数

示例输入:javac Main.java 8 100

这意味着创建 8 个线程并找到从 0 到 100 的素数,包括 100。我的程序有两个命令行参数:第一个是线程数,第二个是素数的范围(0 到 n)。

样本输出:

质数:2 线程#:13

质数:7 线程编号:15

质数:7 线程#:16

质数:11 线程编号:18

然后系统将挂起,并且必须停止该过程:

进程以退出代码 137 结束

我的问题是:

为什么我的线程池超过了它的限制(线程数像 13 或 16,而不是 1-8),我怎样才能让线程不是同时计算相同的数字?我正在考虑使用某种缓存,例如将数字添加到数组列表或其他东西,但我不知道这是否是正确的使用方法。

我可能误解了 ThreadPool 是什么,实际上我在使用与它完全无关的东西。

在这种情况下,我也不确定为什么它会挂起而不是打印从 0 到 100 的所有素数。

如果有更简单的方法来做我想做的事情,我会很想听听。

我会在这里处理这个问题,并且会经常检查这个线程。

是的,这是关于线程的操作系统课程的作业,我通常不会寻求帮助,但我不知所措。所有代码都位于一个文件中。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

private static int MAX_THREADS;
private static int MAX_LIMIT;
private static int numToTest = 0;

public static void main(String[] args) {

int max_threads = Integer.parseInt(args[0]);
int max_limit = Integer.parseInt(args[1]);

MAX_THREADS = max_threads;
MAX_LIMIT = max_limit;

Foo();
}



private static void Foo() {

    class PrimeNumberGen implements Runnable {

        int num = numToTest;

        PrimeNumberGen(int n) {num = n;}

        boolean isPrime(int n) { //first test is 0
            if(n<2) return false;
            if(n==2) return true;
            if(n%2==0) return false;

            int max = n/2;
            for(int i=3; i< max; i=i+2) {
                if (n % i == 0)
                    return false;
            }
                    return true;
        }




        public void  run() {
            numToTest++;
            if(isPrime(num)) {

                System.out.println("Prime Number: "+num+" Thread #:
          "+Thread.currentThread().getId());

            }
            else {
                numToTest++;
            }

        }
    }
    //Thread t = new Thread(new PrimeNumberGen(num));
    //t.start();
    ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
    for (int i = 0;i <= MAX_LIMIT; i++) {
        Runnable worker = new PrimeNumberGen(numToTest);
        executor.execute(worker);
    }


 }
}
4

4 回答 4

3

关于你问题的第二部分,看看 Eratosthenes 的筛子。

改变

Runnable worker = new PrimeNumberGen(numToTest);

Runnable worker = new PrimeNumberGen(i);

您实际上可以丢弃numToTest不再需要的这个变量。

于 2013-09-28T03:16:20.480 回答
3

您的线程 ID 是线程的唯一编号。这可以从任何数字开始,并且不必是连续的。在线程池的生命周期中,您可以拥有超过最大线程数,但在任何时候都不能超过最大值。

顺便说一句,如果您必须找到多个素数,则使用埃拉托色尼筛会更快,因为它的时间复杂度较低。它通常是单线程的,但它仍然会更快。

于 2013-09-28T03:16:28.173 回答
2

重复素数的问题是线程不会一直看到另一个线程的更新,例如

质数:7 线程编号:15

质数:7 线程编号:16(线程 16 看不到线程 15 的值,可能它们在不同的内核上运行)

是因为 numToTest++; 不是线程安全的,因为 numToTest 不是 volatile 并且操作 ++ 不是原子的。我在http://blog.vmlens.com/2013/08/18/java-race-conditions-or-how-to-find-an-irreproducable-bug/下写了一篇博客文章来解释这种类型的错误。

一种解决方案是使用 AtomicInteger,请参阅http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html

由于您没有停止线程池,因此您的程序接缝挂起。请参阅如何在 java 中停止执行 Executor ThreadPool 的执行?这该怎么做。

于 2013-09-28T13:45:27.510 回答
0

关于线程池超过其限制,

改变

System.out.println("Prime Number: "+num+" Thread #:
      "+Thread.currentThread().getId());

System.out.println("Prime Number: "+num+" Thread #:
      "+Thread.currentThread().getName());

线程 ID 是创建该线程时生成的正长数,而不是实际的线程号;调用 getName() 将输出类似

pool-1-thread-3

参考:https ://www.tutorialspoint.com/java/lang/thread_getid.htm

于 2017-10-14T08:41:34.930 回答