Java:两个线程同时对给定范围内的数字求和:当只有一个线程连接到第二个线程时';s的总数太大了
我有两个线程在单个整数数组中求和:Java:两个线程同时对给定范围内的数字求和:当只有一个线程连接到第二个线程时';s的总数太大了,java,multithreading,concurrency,Java,Multithreading,Concurrency,我有两个线程在单个整数数组中求和:[0;100\u 000]。 每个线程都是一个对象,它有min、max和sum字段,我稍后通过对两个线程的结果求和来获得总和。 线程1对[0,20\u 000]范围内的数字求和,而线程2对[20\u 001,100\u 000]范围内的数字求和。正确的thread1的和是200010000,正确的thread2的和是505072704,正确的[01100\u 000]范围内的数字总和是705082704 当两个线程都连接到主方法的线程内时,它工作正常。但是,如果
[0;100\u 000]
。
每个线程都是一个对象,它有min、max
和sum
字段,我稍后通过对两个线程的结果求和来获得总和。
线程1对[0,20\u 000]
范围内的数字求和,而线程2对[20\u 001,100\u 000]
范围内的数字求和。正确的thread1的和是200010000
,正确的thread2的和是505072704
,正确的[01100\u 000]
范围内的数字总和是705082704
当两个线程都连接到主方法的线程内时,它工作正常。但是,如果我只加入第一个线程,那么main方法将在第二个线程完成之前继续打印结果。我理解这种行为。但是,我不明白为什么在这些结果中(此时thread1已完成且其总和正确,而thread2尚未完成且其总和不正确),thread2的总和超过其最大可能总和(505072704
)。我不明白这怎么可能
public class SumNumbers {
public static void main(String[] args) throws Exception {
int min = 0;
int max = 100_000;
int left = 20_000;
int right = 100_000;
int usualSum = 0;
for (int i = min; i<= max; i++) {
usualSum += i;
}
System.out.printf("usual sum: %,d\n", usualSum);
SummerThread s1 = new SummerThread(0, left);
SummerThread s2 = new SummerThread(left + 1, right);
Thread thread1 = new Thread(s1, "left thread");
Thread thread2 = new Thread(s2, "right thread");
thread1.start();
thread2.start();
thread1.join();
// thread2.join();
System.out.printf("left sum: %,d\n", s1.getSum());
System.out.printf("right sum: %,d\n", s2.getSum());
System.out.printf("left + right: %,d\n", s1.getSum() + s2.getSum());
thread2.join();
System.out.printf("right sum: %,d\n", s2.getSum());
System.out.printf("left + right: %,d\n", s1.getSum() + s2.getSum());
}
}
class SummerThread implements Runnable {
private int sum;
private int min;
private int max;
private int id;
private static int count;
public SummerThread(int min, int max) {
this.min = min;
this.max = max;
count++;
id = count;
}
@Override
public void run() {
for (int i = min; i <= max; i++) {
// System.out.println("thread: " + id);
sum += i;
}
}
public int getSum() {return sum;}
}
正确的输出(如果所有.join
均未注释)为:
你的数学不是在这儿吗?从1到n的总和是
n(n+1)/2
,如果将n
替换为100000
,则得到5000050000
。这超过了可以存储在int
中的最大数量,约为20亿。部分和高于最终和的原因可能是您遇到了整数溢出
为了说明这一点,下面的代码片段很有用:
System.out.println((int) 5_000_050_000L); // prints 705082704
如您所见,我们再次找到了您的705082704和,但它是不正确的,只得到下面整数的结果。您的数学不是在这里吗?从1到n的总和是
n(n+1)/2
,如果将n
替换为100000
,则得到5000050000
。这超过了可以存储在int
中的最大数量,约为20亿。部分和高于最终和的原因可能是您遇到了整数溢出
为了说明这一点,下面的代码片段很有用:
System.out.println((int) 5_000_050_000L); // prints 705082704
正如您所看到的,我们再次找到了您的705082704和,但它是不正确的,仅由下面的整数得出。谢谢!我完全没有意识到正确的总数实际上是不同的!我将所有
int
替换为long
无问题。为了使代码更加安全,您可以做一些类似的操作,如在循环中(sum>Long.MAX\u VALUE-i)抛出…,这样可以防止溢出stricmath。addExact(x,y)
可能更好。很好,我不知道这一点谢谢!我完全没有意识到正确的总数实际上是不同的!我将所有int
替换为long
无问题。为了使代码更加安全,您可以做一些类似的事情,比如在循环中(sum>Long.MAX\u VALUE-i)抛出…,这样可以防止溢出stricmath.addExact(x,y)
可能更好。很好,我不知道这一点
usual sum: 705,082,704
left sum: 200,010,000
right sum: 1,625,006,320
left + right: 1,825,016,320
right sum: 505,072,704
left + right: 705,082,704
usual sum: 705,082,704
left sum: 200,010,000
right sum: 505,072,704
left + right: 705,082,704
right sum: 505,072,704
left + right: 705,082,704
System.out.println((int) 5_000_050_000L); // prints 705082704