这两种并发实现哪个更好更快

Which one of these two concurrent implementations is a better faster

我有两个并行生成素数的实现。核心代码取自 Whosebug 中的另一个 post。

我想知道这些实现中的哪一个是首选,为什么?另外,是否有更好更快的解决方案?

实施 1:

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

public class PrimeThreads {

    private static int currentPrime = 0;

    public static void main(String[] args) {

        Object lock = new Object();

        Thread primerGenThread = new Thread(() -> {
            String threadName = Thread.currentThread().getName();
            System.out.println("Starting thread: " + threadName);
            int currentPrimeNo = 0;
            synchronized (lock) {
                try {
                    currentPrimeNo = generateNextPrime();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }
            System.out.println("Prime Number Associated with this thread " + threadName + " is: " + currentPrimeNo);
            System.out.println("Completed thread: " + threadName);
        });

        System.out.println("****This is where the project starts*****");

        Scanner reader = new Scanner(System.in);
        System.out.print("Enter number of threads you want to create: ");
        int n = reader.nextInt();
        reader.close();

        ExecutorService executor = Executors.newFixedThreadPool(n);
        for(int i=1;i<=n; i++) {
            executor.submit(primerGenThread);
        }
        executor.shutdown();
        try {
            executor.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println("****This is where the project ends*****");

    }

    private static int generateNextPrime() throws InterruptedException {

        long startTime = System.nanoTime();

        currentPrime++;
        if (currentPrime < 2) {
            currentPrime = 2;
            return currentPrime;
        }
        for (int i = 2; i < currentPrime; i++) {
            if (currentPrime % i == 0) {
                currentPrime++;
                i = 2;
            } else {
                continue;
            }
        }       

        long endTime = System.nanoTime();
        System.out.println("Time taken: " + (endTime - startTime) + " naoseconds.");
        return currentPrime;
    }

}

和实施 2:

import java.util.Scanner;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class PrimeAsyncThreads {

    private static int currentPrime = 0;

    public static void main(String[] args) {

        System.out.println("****This is where the project starts*****");

        Scanner reader = new Scanner(System.in);
        System.out.print("Enter number of threads you want to create: ");
        int n = reader.nextInt();
        reader.close();

        ExecutorService executor = Executors.newFixedThreadPool(n);

        for (int i = 1; i <= n; i++) {
            CompletableFuture.supplyAsync(() -> {
                try {
                    return generateNextPrime();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
                return n;
            }, executor).thenAccept(s -> System.out.println("Prime Number Associated with this thread "
                    + Thread.currentThread().getName() + " is: " + currentPrime));
        }

        executor.shutdown();

        try {
            executor.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        System.out.println("****This is where the project ends*****");
    }

    private static int generateNextPrime() throws InterruptedException {

        long startTime = System.nanoTime();

        currentPrime++;
        if (currentPrime < 2) {
            currentPrime = 2;
            return currentPrime;
        }
        for (int i = 2; i < currentPrime; i++) {
            if (currentPrime % i == 0) {
                currentPrime++;
                i = 2;
            } else {
                continue;
            }
        }

        long endTime = System.nanoTime();
        System.out.println("Time taken: " + (endTime - startTime) + " naoseconds.");
        return currentPrime;
    }
}

感谢您的建议和帮助。

编辑: 还注意到第二个实现不保证每个线程都会得到一个新的素数。在这种情况下,有时多个线程会获得相同的 currentPrime 变量值。

谢谢。

这些实现之间的主要区别在于它们的执行方式。

实现1基本等于顺序执行。使用线程没有任何优势,因为如何使用同步块。 在生成下一个素数之前,每个线程都等待前一个线程完成。

您已经注意到实现 2 多次计算同一个素数。这是因为没有同步。只有计数器 currentPrime 用于以某种方式控制下一个线程中应将哪个数字视为质数。

因此,这两种实现都无法并行计算素数以产生可行的结果。

想想套路。您使用一个值来确定它是否是质数。这个值应该是每个线程进行计算的输入。 现在唯一要考虑的是如何让这个值线程安全,确保它只被使用一次。

这可以实现,例如通过为 currentPrime.

使用原子变量

另一个改进可能是在 generateNextPrime() 方法之外增加 currentPrime。此方法可以将值作为参数。像

generateNextPrime(currentPrime.incrementAndGet());