我有一个PrimeNumbers类程序。它显示x是否为素数。 x是程序中分析的数字。
程序需要多长时间才能知道答案。 x很大,知道答案需要9秒钟。如何使用更多线程更快地运行程序?在这种情况下,我很难掌握如何实现线程。
public class PrimeNumbers {
private static int x = 2147483647;
public static boolean prime= true;
public static void main(String[]args){
long start, end, elapsetime;
start= System.currentTimeMillis();
for(int y=2; y<x; y++){
if(x % y == 0){
prime=false;
System.out.println(y);
break;
}
}
end = System.currentTimeMillis();
elapsetime = end - start;
System.out.println("Prime: " + prime);
System.out.println(elapsetime+ " mill sec " + (elapsetime / 1000
+ " seconds."));
}
}
答案 0 :(得分:3)
我会忽略您是否拥有最有效的方法,并专注于如何通过更多线程更快地使用当前代码。
您目前正在遍历2 -> x
中的所有数字并执行简单测试。提高性能的方法可能是将此任务拆分为 Z 块并启动 Z 线程以并行执行测试。
E.g。如果你有两个线程,你将有一个线程检查2 -> x/2
,另一个检查x/2 + 1 -> x
。如果全局(可能是volatile
)标志设置为true,则每个线程都应该从测试中断,这表明另一个线程已经反驳了该素数。
答案 1 :(得分:2)
您的素性测试效率非常低,您在每个小于x的数字上循环。
你怎么能改善它?这link should be helpful.
一个好的算法是AKS测试,或者是Eratosthenes的Sieve。下面的代码实现了wiki文章中的一种算法,它比你发布的测试更有效。
public static boolean isPrime(long n) {
// http://en.wikipedia.org/wiki/Primality test
if (n <= 3) return n > 1;
if (n % 2 == 0 || n % 3 == 0) return false;
for (int i = 5; i*i <=n; i+=6) {
if (n % i == 0 || n % (i+2) == 0) return false;
}
return true;
}
}
答案 2 :(得分:1)
如果你想要一个更好的算法,Munyari已经建议了一个。
忽略以下示例可以帮助您如何并行执行算法(即使它是一个愚蠢的算法)
我们需要一个实现Callable接口的类(类似于Runnable)。它应该得到工作的一部分并计算它。
public class PrimeChecker implements Callable<Boolean> {
private final long numberToCheck;
private final long start;
private final long end;
public PrimeChecker(long numberToCheck, long start, long end) {
this.numberToCheck = numberToCheck;
this.start = start;
if (end >= numberToCheck) {
this.end = numberToCheck - 1;
}else{
this.end = end;
}
System.out.println("A PrimeChecker with start " + start + " and end " + end + " values to check number "
+ numberToCheck);
}
@Override
public Boolean call() throws Exception {
boolean prime = true;
long current = start;
if (current != 2 && (current % 2 == 0)) {
current = current + 1;
}
for (; current < end; current = current + 2) {
if (numberToCheck % current == 0) {
prime = false;
System.out.println("The number " + numberToCheck + " is divisable with " + current);
return prime;
}
}
return prime;
}
}
它只是start
来自一个数字并检查给定数字numberToCheck
是否可以分割并继续直到它达到数字end
。
在Main类中,我们必须创建多个PrimeChecker作业并并行执行它们。为此,我们使用Java的ExecutorService。它为我们创建了一个线程池。然后我们可以在多个PrimeCheckers上分配工作。最后,我们执行invokeAll
ExecutorService
方法。这为我们提供了一个Future列表,其中包含我们并行执行的每个作业的结果。
public class Main {
public static boolean prime= true;
public static void main(String[] args) throws InterruptedException, ExecutionException {
long startTime = System.currentTimeMillis();
long numberToCheck = 5333334345L;
int numberOfThreads = 10;
System.out.println("Checking if the number " + numberToCheck + " ...");
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
List<PrimeChecker> primeCheckers = new ArrayList<PrimeChecker>();
long partOfNumber = (long) Math.ceil((double)numberToCheck/ numberOfThreads);
long start = 2 ;
long end = 0;
for(int i = 0; i < numberOfThreads; i++){
end = end + partOfNumber;
primeCheckers.add(new PrimeChecker(numberToCheck, start, end));
start = end+1;
}
List<Future<Boolean>> futures = executor.invokeAll(primeCheckers);
for(Future<Boolean> future : futures){
prime = future.get();
if(prime == false){
break;
}
}
System.out.println("The number " + numberToCheck + " is " + (prime ? "a prime" :"NOT !!!!!!!!!!!!!!!!!!!! a prime") + " number");
long endTime = System.currentTimeMillis();
long elapsetime = endTime - startTime;
System.out.println(elapsetime + " milliseconds");
System.exit(0);
}
}
您可以尝试使用不同数量的线程(请参阅numberOfThreads
变量)来查看差异。
我希望它能够帮助您更好地理解多线程。 (注意:它只是整个线程主题的一小部分)
答案 3 :(得分:0)
如果您不需要自己实施质量检查,我建议使用API。您可以根据需要控制确定性。在该示例中,它是:1-(1/2) 100
public static void main(String[] args) {
BigInteger mersenne = new BigInteger("2").pow(521).add(BigInteger.ONE.negate());
System.out.println("digits of the number: " + mersenne.toString().length());
long start = System.currentTimeMillis();
final int certainty = 100;
boolean isPrime = mersenne.isProbablePrime(certainty);
System.out.println("elapsed millis: " + (System.currentTimeMillis() - start));
System.out.println("isPrime : " + isPrime);
}
修改强> 这是建议示例的优化版本。
public class PrimeNumbers {
private static int x = 2147483647;
public static boolean prime= true;
public static void main(String[]args){
long start, end, elapsetime;
int divisor = 1;
start= System.currentTimeMillis();
if (x % 2 == 0) {
prime = false;
divisor = 2;
} else {
// - you can use an increment of two
// because you don't need to check
// for a divisor which is a multiple
// of two
// - you don't need to check for any divisor
// which is greater than x/2
for(int y=3; y < x/2; y += 2){
if(x % y == 0){
prime=false;
divisor = y;
break;
}
}
}
end = System.currentTimeMillis();
System.out.println("Prime: " + prime);
if (!prime) {
System.out.println("divisible by: " + divisor);
}
elapsetime = end - start;
System.out.println(elapsetime+ " mill sec " + (elapsetime / 1000
+ " seconds."));
}
}