【问题标题】:Finding Prime numbers n...n using a ThreadPool使用 ThreadPool 查找素数 n...n
【发布时间】:2013-09-28 03:06:13
【问题描述】:

所以正如标题所示,我试图找到从 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);
    }


 }
}

【问题讨论】:

  • 请注意,您需要在代码末尾调用 executor.shutdown()
  • 尝试将工作分离到线程中,例如线程号 1 用于 0 到 100 的数字,第二个用于 101 到 200 等等。你也可以实现自己的thread pool

标签: java multithreading concurrency primes inner-classes


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    关于你问题的第二部分,看看埃拉托色尼筛。

    改变

    Runnable worker = new PrimeNumberGen(numToTest);

    Runnable worker = new PrimeNumberGen(i);

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

    【讨论】:

      【解决方案3】:

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

      素数: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

      您的程序接缝挂起,因为您没有停止线程池。请参阅How to stop the execution of Executor ThreadPool in java? 如何执行此操作。

      【讨论】:

        【解决方案4】:

        关于线程池超过其限制,

        改变

        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

        【讨论】:

          猜你喜欢
          • 2011-04-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-22
          相关资源
          最近更新 更多