Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的线程与计算_Java_Multithreading_Sum_Primes - Fatal编程技术网

Java中的线程与计算

Java中的线程与计算,java,multithreading,sum,primes,Java,Multithreading,Sum,Primes,我是java新手,我正在尝试编写一个包含两个参数的程序: 素数求和的次数 必须在其中执行此操作的线程数 因此,我使用了一个名为Eratosthene的方法,它存储了一个布尔值的数组,如果一个数字是素数,我们将其标记为true,然后将该数字的所有倍数标记为false 我尝试将我的数组划分为每个线程的子数组,并在每个子数组中执行操作,最后对子数组的所有结果求和 但是我不知道我哪里做错了:有时候这个程序没有给出好的结果 这是我的代码: SumPrime.java import java.util.*;

我是java新手,我正在尝试编写一个包含两个参数的程序:

  • 素数求和的次数
  • 必须在其中执行此操作的线程数
  • 因此,我使用了一个名为Eratosthene的方法,它存储了一个布尔值的数组,如果一个数字是素数,我们将其标记为true,然后将该数字的所有倍数标记为false

    我尝试将我的数组划分为每个线程的子数组,并在每个子数组中执行操作,最后对子数组的所有结果求和

    但是我不知道我哪里做错了:有时候这个程序没有给出好的结果

    这是我的代码:

    SumPrime.java

    import java.util.*;
    import java.util.concurrent.*;
    
    public class SumPrimes {
    
        private boolean array[];
        private int numberOfWorkers;
        private Semaphore allFinished;
    
        public SumPrimes(int num, int threads){
            array = new boolean[num];
            numberOfWorkers = threads;
            for (int i = 2; i < num; i++)
                array[i] = true;
        }
    
        private class SumParallel extends Thread {
            int min;
            int max;
            long sum;
    
            SumParallel(int min, int max){
                this.min = min;
                this.max = max;
                sum = 0;
            }
    
            public void run() {
                for (int i = min; i < max; i++) {
                    if (array[i]) {
                        for (int j = min; j*i < array.length; j++) {
                            array[i*j] = false;
                        }
                        sum += i;
                    }
                }
                allFinished.release();
            }
    
            public long getSum() {
                return sum;
            }
        }
    
        public void SumInParallel() {
            allFinished = new Semaphore(0);
    
            List<SumParallel> workers = new ArrayList<SumParallel>();
            int lengthOfOneWorker = array.length / numberOfWorkers;
            for (int i = 0; i < numberOfWorkers; i++) {
                int start = i * lengthOfOneWorker;
                int end = (i+1) * lengthOfOneWorker;
    
                if (i == numberOfWorkers - 1)
                    end = array.length;
                SumParallel worker = new SumParallel(start, end);
                workers.add(worker);
                worker.start();
            }
    
            try {
                allFinished.acquire(numberOfWorkers);
            } catch (InterruptedException ignored) {}
    
            int sum = 0;
            for (SumParallel w : workers){
                sum += w.getSum();
            }
    
            System.out.println("The sum of prime numbers is: " + sum);
        }
    
        public static void main(String[] args) {
            int limitNum = Integer.parseInt(args[0]);
            int threadNum = Integer.parseInt(args[1]);
            SumPrimes sum_primes = new SumPrimes(limitNum, threadNum);
            sum_primes.SumInParallel();
        }
    }
    

    我愿意接受任何改进代码的建议。

    您需要完全重新思考线程的逻辑

    不同线程不能访问相同范围的
    数组
    ,例如,如果线程具有
    min=100
    max=150
    ,则只能使用和/或更改范围为100到149(包括)的元素

    您的代码:

    for (int i = min; i < max; i++) {
        if (array[i]) {
            for (int j = min; j*i < array.length; j++) {
                array[i*j] = false;
    
    这给了我们主要的逻辑:

    maxPrime=(int)Math.sqrt(max);
    
    对于(int prime=2;prime我认为您的问题在于以下代码:

       public void run() {
            for (int i = min; i < max; i++) {
                if (array[i]) {
                    for (int j = min; j*i < array.length; j++) {
                        array[i*j] = false;
                    }
                    sum += i;
                }
            }
            allFinished.release();
        }
    
    public void run(){
    对于(int i=min;i
    想象一下,你后面的一个线程,工作在列表的末尾。第一个项目不是prime,但是识别它不是prime的工作还没有完成——它来自另一个线程,而该线程刚刚开始。因此你相信该值是prime(它还没有标记为NOT prime),并相应地工作


    如果您提供的示例产生了不好的结果,我们可以很容易地测试理论。

    多线程通常也意味着您希望加快速度。因此,首先值得回顾一下您的初始设计,并在单个线程上加快速度。然后,这是一个需要克服的目标。此外,对于比较运行时而不编写优化的代码来说基准测试,您需要一个“可见”长度的运行时。
    在我的机器上,使用“设置”

    您的原始代码

    for(int i=2;i<max;i++)
        if(!sieve[i]) {
            for(int j=i*2;j<max;j+=i)
                sieve[j]=true;
            sum+=i;
        }
    
    这一个在我的机器上运行14-16秒。获得了显著的收益,并且还没有涉及线程


    然后是线程,
    if(!sieve[i])
    的问题:在计算总和时,在小于
    i
    的低素数的内循环超过
    i
    之前,不得进行此类检查,因此
    sieve[i]
    确实会告诉您它是否为素数。例如,如果线程像
    那样运行(int i=4;i相关:您应该使用a,而不是a。请参阅,例如,如果您提供了一个运行示例,说明产生错误的值以及实际值应该是什么,这会很有帮助。@JosephLarson例如,如果我使用
    java SumPrimes 200 4
    的话,实际答案是
    4227
    ,如果我用这个命令多次运行我的程序,有时我会得到这是一个好答案,但有时我得到的答案要么离好结果太远,要么太接近好结果,这就是所谓的竞争条件,这就是为什么多线程编程可能很困难的原因,因为当你做错事时,结果会有所不同,而且可能在大多数情况下看起来都是正确的,所以你可能甚至不知道(一开始)。为什么这里有竞态条件?因为第一个线程更新了其他线程使用的数组值。@Andreas我刷新了您发送的链接,但我看不到不使用
    信号量的理由。
    。您能解释一下为什么我应该使用
    CountDownLatch
    ?例如,您可以多次运行
    java SumPrimes 200 4
    查看答案。正确的结果必须是4227,如果您多次运行此命令,您会看到它给出了正确的答案,但有时,它给出的答案是错误的,听起来像是竞争条件,这就是我在回答中试图解释的。我不认为您可以将阵列拆分为多个部分并以这种方式进行测试是的。我认为你能做的最好的事情就是分开标记false,即使这样,你也不能比你的子线程标记false更快。但是在第二个循环中,我说如果
    I*j
    。这意味着我总是一直到范围,我永远不会通过范围,不是吗?@Mohammadreza说数组是200个元素,而你呢有4个线程。然后第三个线程进入进程范围100-149(包括),外部循环将在该范围内迭代
    i
    。但是
    j
    将从100开始迭代,
    j*i
    从10000开始,这不是
    经过一些思考和测试后,我总是从哪里开始,我真的不知道如何解决这个问题。因为我想做的是去修改其他子数组。我不知道I don’我不想只停留在每个线程的每个子数组的范围内。我希望每个线程都修改其他线程的子数组。对于一般素数测试,您的观察是正确的,当它足以运行除数到所讨论的数字的平方根时。但是这里的
    sum+=I;
    部分很重要,所以
    I
    必须运行到
    max
    ,而这个内部的
    for
    对于大数没有任何作用,如果
    ,可以用额外的
    if
    来强调这一点,但是这个检查只是额外的一步,没有任何好处。谢谢你更新了答案。我想知道在这个版本中,每个线程是否只修改其子数组,或者every线程也会修改比他更大的其他线程的子数组?非常感谢您的深入解释。您提出了一些很好的观点。
    private static long sumPrimes(boolean[] seedPrime, boolean[] rangePrime, int min, int max/*inclusive*/) {
        // Initialize range
        for (int i = Math.max(min, 2); i <= max; i++) {
            rangePrime[i - min] = true;
        }
    
        // Mark non-primes in range
        int maxPrime = (int) Math.sqrt(max + 1); // extra to be sure no "float errors" occur
        for (int prime = 2; prime <= maxPrime; prime++) {
            if (seedPrime[prime]) {
                int minMultiple = (min + prime - 1) / prime * prime;
                if (minMultiple <= prime)
                    minMultiple = prime * 2;
                for (int multiple = minMultiple; multiple <= max ; multiple += prime) {
                    rangePrime[multiple - min] = false;
                }
            }
        }
    
        // Sum the primes
        long sum = 0;
        for (int prime = min; prime <= max; prime++) {
            if (rangePrime[prime - min]) {
                sum += prime;
            }
        }
        return sum;
    }
    
    public static void main(String[] args) {
        test(1000, 3);
        test(100000000, 4);
    }
    public static void test(int n, int threadCount) {
        long start = System.nanoTime();
        long sum = sumPrimes(n, threadCount);
        long end = System.nanoTime();
        System.out.printf("sumPrimes(%,d, %d) = %,d (%.9f seconds)%n",
                          n, threadCount, sum, (end - start) / 1e9);
    }
    
    threads[t] = new Thread(() ->
        totalSum.addAndGet(sumPrimes(seedPrime, new boolean[max - min + 1], min, max))
    );
    
    threads[t] = new Thread() {
        @Override
        public void run() {
            totalSum.addAndGet(sumPrimes(seedPrime, new boolean[max - min + 1], min, max));
        }
    };
    
       public void run() {
            for (int i = min; i < max; i++) {
                if (array[i]) {
                    for (int j = min; j*i < array.length; j++) {
                        array[i*j] = false;
                    }
                    sum += i;
                }
            }
            allFinished.release();
        }
    
    int max = 1_000_000_000;
    boolean sieve[] = new boolean[max];
    long sum = 0; // will be 24739512092254535 at the end
    
    for(int i=2;i<max;i++)
        if(!sieve[i]) {
            for(int j=i*2;j<max;j+=i)
                sieve[j]=true;
            sum+=i;
        }
    
    int maxunique=(int)Math.sqrt(max);
    for(int i=2;i<=maxunique;i++)
        if(!sieve[i]) {
            for(int j=i*2;j<max;j+=i)
                sieve[j]=true;
            sum+=i;
        }
    for(int i=maxunique+1;i<max;i++)
        if(!sieve[i])
            sum+=i;
    
    for(int i=2;i<=maxunique;i++)
        if(!sieve[i])
            for(int j=i*2;j<max;j+=i)
                sieve[j]=true;
    
    int numt=4;
    Thread sumt[]=new Thread[numt];
    long sums[]=new long[numt];
    for(int i=0;i<numt;i++) {
        long ii=i;
        Thread t=sumt[i]=new Thread(new Runnable() {
            public void run() {
                int from=(int)Math.max(ii*max/numt,2);
                int to=(int)Math.min((ii+1)*max/numt,max);
                long sum=0;
                for(int i=from;i<to;i++)
                    if(!sieve[i])
                        sum+=i;
                sums[(int)ii]=sum;
            }
        });
        t.start();
    }
    
    for(int i=0;i<sumt.length;i++) {
        sumt[i].join();
        sum+=sums[i];
    }
    
    List<Thread> threads=new ArrayList<>();
    for(int i=2;i<=maxunique;i++)
        if(!sieve[i]) {
            int ii=i;
            Thread t=new Thread(new Runnable() {
                public void run() {
                    for(int j=ii*2;j<max;j+=ii)
                        sieve[j]=true;
                }
            });
            t.start();
            threads.add(t);
        }
    //System.out.println(threads.size());
    for(int i=0;i<threads.size();i++)
        threads.get(i).join();
    
    for(int i=maxunique+1;i<max;i++)
        if(!sieve[i])
            sum+=i;
    
    for(int j=ii*2;j<max && !sieve[ii];j+=ii)
    
    ExecutorService es=Executors.newWorkStealingPool();
    ExecutorCompletionService<Object> ecs=new ExecutorCompletionService<Object>(es);
    
    int count=0;
    
    for(int i=2;i<=maxunique;i++)
        if(!sieve[i]) {
            int ii=i;
            count++;
            ecs.submit(new Callable<Object>() {
                public Object call() throws Exception {
                    // if(!sieve[ii])
                    for(int j=ii*2;j<max /**/ && !sieve[ii] /**/;j+=ii)
                        sieve[j]=true;
                    return null;
                }
            });
        }
    System.out.println(count);
    while(count-->0)
        ecs.take();
    es.shutdown();
    long sum=0;
    
    for(int i=2;i<max;i++)
        if(!sieve[i])
            sum+=i;
    
    long sum=0;
    for(int i=2;i<=maxunique;i++)
        if(!sieve[i]) {
            sum+=i;
            int ii=i;
            IntStream.range(1, (max-1)/i).parallel().forEach(
                j -> sieve[ii+j*ii]=true);
        }
    
    for(int i=maxunique+1;i<max;i++)
        if(!sieve[i])
            sum+=i;
    
    int limit=2;
    do {
        int upper=Math.min(maxunique+1,limit*limit);
        for(int i=limit;i<upper;i++)
            if(!sieve[i]) {
                sum+=i;
                for(int j=i*2;j<max;j+=i)
                    sieve[j]=true;
            }
        limit=upper;
    } while(limit<=maxunique);
    
    for(int i=limit;i<max;i++)
        if(!sieve[i])
            sum+=i;
    
    ExecutorService es=Executors.newWorkStealingPool();
    ExecutorCompletionService<Object> ecs=new ExecutorCompletionService<>(es);
    
    int limit=2;
    int count=0;
    do {
        int upper=Math.min(maxunique+1,limit*limit);
        for(int i=limit;i<upper;i++)
            if(!sieve[i]) {
                sum+=i;
                int ii=i;
                count++;
                ecs.submit(new Callable<Object>() {
                    public Object call() throws Exception {
                        for(int j=ii*2;j<max;j+=ii)
                            sieve[j]=true;
                        return null;
                    }
                });
            }
        while(count>0) {
            count--;
            ecs.take();
        }
        limit=upper;
    } while(limit<=maxunique);
    
    es.shutdown();
    
    for(int i=limit;i<max;i++)
        if(!sieve[i])
            sum+=i;