Java多线程中的意外结果(尽管存在锁)
我正在努力使用一些应该使用线程计算平方和的练习代码。 出于某种原因,尽管使用了锁,但我还是得到了不一致的结果,同时确保我锁定的是对象,而不是局部项/变量等 当我添加日志以了解行为时,代码运行速度要慢得多,执行得也很好。当减少到一个线程时也是如此。但是,一旦我运行多个线程,它的行为就不可预测了。 结果应该是 我的代码:Java多线程中的意外结果(尽管存在锁),java,multithreading,reentrantlock,Java,Multithreading,Reentrantlock,我正在努力使用一些应该使用线程计算平方和的练习代码。 出于某种原因,尽管使用了锁,但我还是得到了不一致的结果,同时确保我锁定的是对象,而不是局部项/变量等 当我添加日志以了解行为时,代码运行速度要慢得多,执行得也很好。当减少到一个线程时也是如此。但是,一旦我运行多个线程,它的行为就不可预测了。 结果应该是 我的代码: package com.yaniv.concurrency; import java.sql.Timestamp; import java.util.concurrent
package com.yaniv.concurrency;
import java.sql.Timestamp;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class SumSquaresSync implements Runnable {
ReentrantLock nextLock = new ReentrantLock();
ReentrantLock sumLock = new ReentrantLock();
Long sum = new Long(0);
int min, max;
Integer next = new Integer(0);
int threadBatchSize = 10;
static final boolean LOG = false;
@Override
public void run() {
long localSum = 0;
int[] batch = new int[threadBatchSize];
while (next <= max) {
nextLock.lock();
if (this.next <= max) {
{
for (int i = 0; i < threadBatchSize; i++) {
batch[i] = ((next + i <= max) ? (next + i) : 0);
}
next += threadBatchSize;
}
}
nextLock.unlock();
if (LOG) {
synchronized (System.out) {
System.out.print(Thread.currentThread().getName() + " got batch " + batch.toString() + ": ");
for (int i = 0; i < threadBatchSize; i++) {
System.out.print(batch[i] + ", ");
}
System.out.println();
}
}
for (int i : batch) {
localSum += Math.pow(i, 2);
}
}
sumLock.lock();
sum += localSum;
sumLock.unlock();
if (LOG) {
safePrintln(Thread.currentThread().getName() + " terminated, localSum = " + localSum);
}
}
private long executeSumSquares(int min, int max, int numberOfThreads, int threadBatchSize) throws Exception {
this.min = min;
this.max = max;
this.next = min;
this.threadBatchSize = threadBatchSize;
this.sum = 0L;
ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);
for (int i = 0; i < numberOfThreads; i++) {
if (LOG) {
System.out.format("Adding thread %d%n", i);
}
executorService.execute(new SumSquaresSyncThread(this));
}
executorService.shutdown();
executorService.awaitTermination(5_000L, TimeUnit.MILLISECONDS);
return sum;
}
public static void main(String[] args) throws Exception {
SumSquaresSync SumSquaresSync = new SumSquaresSync();
long total;
int iteration = 0;
Timestamp startTime, endTime;
do {
iteration++;
startTime = new Timestamp(System.currentTimeMillis());
total = SumSquaresSync.executeSumSquares(1, 10000, 1, 5);
endTime = new Timestamp(System.currentTimeMillis());
System.out.println("==========================================");
System.out.format("Total sum: %,8d, elapsed time %d, iteration %d%n", total, (endTime.getTime() - startTime.getTime()), iteration);
System.out.println("==========================================");
} while (iteration < 10); //(total == 333383335000L);
}
public void safePrintln(String s) {
synchronized (System.out) {
System.out.println(s);
}
}
public void safePrint(String s) {
synchronized (System.out) {
System.out.print(s);
}
}
}
正确的结果应为333383335000。
有人能说出我遗漏了什么吗?(摘自评论)
您的while(下一个(从注释中复制)
你的while(下一个while)(下一个问题解决了,谢谢@CherryDT!我已经为此挣扎了好几个小时。真的很感激!我意识到它作为完整的答案是有意义的。添加了它,所以你可以接受它作为解决方案。欢迎你!Re,“当我添加日志时……代码……执行得很好。”曾经在那里。完成了。有时你可以通过将事件记录到内存中的缓冲区而不是写入文件来获得线索,然后在之后转储缓冲区。YMMV。这是一个有用的技巧。谢谢!你的虽然(下一个问题解决了,谢谢@CherryDT!我已经为此挣扎了好几个小时。真的很感激!我意识到它作为一个完整的答案是有意义的。添加了它,所以你可以接受它作为解决方案。欢迎你!Re,“当我添加日志时……代码……执行得很好。”曾经在那里。完成了。有时候你可以通过将事件记录到内存中的缓冲区而不是写入文件来获得线索,然后再转储缓冲区。YMMV。这是一个有用的提示。谢谢!
Total sum: 347,938,671,335, elapsed time 16, iteration 1
Total sum: 342,283,818,850, elapsed time 10, iteration 2
Total sum: 336,257,779,565, elapsed time 10, iteration 3
Total sum: 336,233,345,285, elapsed time 9, iteration 4
Total sum: 337,663,242,000, elapsed time 8, iteration 5
Total sum: 336,779,784,290, elapsed time 10, iteration 6
Total sum: 335,474,886,225, elapsed time 10, iteration 7
Total sum: 338,825,524,135, elapsed time 8, iteration 8
Total sum: 335,820,751,880, elapsed time 10, iteration 9
Total sum: 335,083,150,300, elapsed time 8, iteration 10