使用 java 中的多线程基础知识查找 [1, n] 范围内可被 3、5 或 7 整除的所有整数的总和

Pha*_*tom 6 java multithreading

问题解释:您必须编写一个多线程程序,查找 [1, n] 范围内可被 3、5 或 7 整除的所有整数。返回所有唯一整数的总和作为您的答案。请注意,诸如 15(3 和 5 的倍数)之类的整数仅计算一次。正整数 n > 0 作为输入提供给您。创建解决问题所需的任意数量的线程。您可以使用线程池来获得奖励积分。

Example:
Input: n = 10
Output: sum = 40
Explanation: Numbers in the range [1, 10] that are divisible by 3, 5, or 7 are:
3, 5, 6, 7, 9, 10. The sum of these numbers is 40.
Run Code Online (Sandbox Code Playgroud)

我遇到的解决方案和问题:在这个程序中,我创建了三个线程,每个线程分别查找除以 3,5 和 7 的整数,然后它将它们全部存储在除数数组列表中,并通过以下代码它将删除数组列表中重复的:

Set<Integer> set = new HashSet<>(dividends);
    dividends.clear();
    dividends.addAll(set);
Run Code Online (Sandbox Code Playgroud)

我使用了老师提供的一些测试用例,问题是在测试用例中 n=1000 和 n=76293 sum 不会显示预期的金额:

n=1000
expected sum:272066
actual sum:247377
Run Code Online (Sandbox Code Playgroud)

另一个问题是,每次运行测试用例时,实际总和都会不断变化。有人可以告诉我我的代码有什么问题以及如何修复它

我的代码:

import java.util.*;
public class FindMultiples
{

public static ArrayList<Integer> dividends = new ArrayList<>();
public static int temp = 0;
public static synchronized void increment(){
    dividends.add(temp);
}
public static class thread implements Runnable{

    public int divisor;
    public int n;

    public thread(int n , int divisor){
        this.n=n;
        this.divisor=divisor;
    }

    @Override
    public void run() {

        for (int i=1 ; i<=n ; i++){
            if (i%divisor==0){
                temp=i;
                increment();
            }
        }
    }
}

public int getSum(int n) {
    int sum = 0;
    Thread thread1 = new Thread(new thread(n,3));
    Thread thread2 = new Thread(new thread(n,7));
    Thread thread3 = new Thread(new thread(n,5));
    
    thread3.start();
    thread2.start();
    thread1.start();
    try {
        thread3.join();
        thread2.join();
        thread1.join();
    }catch (InterruptedException e){

    }
    Set<Integer> set = new HashSet<>(dividends);
    dividends.clear();
    dividends.addAll(set);

    for (int i : dividends){
        sum+=i;
    }

    return sum;
}

public static void main(String[] args) {
}
}
Run Code Online (Sandbox Code Playgroud)

小智 2

您的主要问题很可能是您正在同步increment()方法,而不是同步temp变量。当一个线程尝试执行increment()方法时,第二个线程正在更改临时变量的值。在调试中运行您的代码并检查它。

最好将值直接发送到increment(),而不是将其存储在temp 中。查看我编辑的代码:

import java.util.*;
public class FindMultiples
{

  public static ArrayList<Integer> dividends = new ArrayList<>();
  public static synchronized void increment(int temp){
     dividends.add(temp);
  }
  
  public static class MyThread implements Runnable{

    public int divisor;
    public int n;

    public MyThread(int n , int divisor){
        this.n=n;
        this.divisor=divisor;
    }

    @Override
    public void run() {

        for (int i=1 ; i<=n ; i++){
            if (i%divisor==0){
                increment(i);
            }
        }
    }
  }

  public int getSum(int n) {
    int sum = 0;
    Thread thread1 = new Thread(new MyThread(n,3));
    Thread thread2 = new Thread(new MyThread(n,7));
    Thread thread3 = new Thread(new MyThread(n,5));

    thread3.start();
    thread2.start();
    thread1.start();
    try {
        thread3.join();
        thread2.join();
        thread1.join();
    }catch (InterruptedException e){
        System.out.println(e.getMessage());
    }
    Set<Integer> set = new HashSet<>(dividends);
    dividends.clear();
    dividends.addAll(set);

    for (int i : dividends){
        sum+=i;
    }

    return sum;
  }

  public static void main(String[] args) {
    FindMultiples findMultiples = new FindMultiples();
    System.out.println(findMultiples.getSum(1000));
  }
}
Run Code Online (Sandbox Code Playgroud)