concurrency - 为什么 CyclicBarrier 在我的程序中并不总是按预期工作?
问题描述
我做了一个简单的程序来计算矩阵中的行总和。我想同时这样做,所以我使用了 CyclicBarrier。有时它会按预期工作,但有时会出现小错误,就像程序错过了一个或两个数字一样。
这是我的代码:
package synchronizacja;
import java.util.concurrent.CyclicBarrier;
public class SumyWierszamiSekwencyjnie {
private static final int ROWS = 10;
private static final int COLUMNS = 100;
private static int sum;
private static CyclicBarrier barrier = new CyclicBarrier(COLUMNS, new Tmp());
private static class Tmp implements Runnable {
@Override
public void run() {
System.out.println("The sum is: " + sum);
sum = 0;
}
}
private static class CountByColumns implements Runnable {
private void CriticalSection(int wiersz) {
sum += wiersz;
}
@Override
public void run() {
for (int i = 0; i < ROWS; i++) {
CriticalSection(i);
try { barrier.await(); }
catch (Exception e) { System.out.println("Exception"); }
}
}
}
public static void main(String[] args) {
for (int i = 0; i < COLUMNS; i++) {
new Thread(new CountByColumns()).start();
}
}
}
输出应该是
The sum is: 0
The sum is: 100
The sum is: 200
The sum is: 300
The sum is: 400
The sum is: 500
The sum is: 600
The sum is: 700
The sum is: 800
The sum is: 900
有时它是,但更多时候它会显示类似的东西
The sum is: 0
The sum is: 100
The sum is: 200
The sum is: 297
The sum is: 400
The sum is: 500
The sum is: 600
The sum is: 700
The sum is: 800
The sum is: 900
为什么会这样?我在想这可能是因为 Tmp 类中的 run() 不必是原子的,所以当前线程可能会在将 sum 设置为 0 之前跳到计算另一行的总和。如果是这样,我该如何防止这种情况?
解决方案
我在想这可能是因为 Tmp 类中的 run() 不必是原子的,所以当前线程可能会在将 sum 设置为 0 之前跳到计算另一行的总和。
我不这么认为,CB.await 的 javadoc指定
如果当前线程是最后到达的线程,并且在构造函数中提供了非空屏障动作,则当前线程在允许其他线程继续之前运行该动作。
有两个问题,第一个是潜在的多核可见性执行屏障操作的线程可能还没有看到 sum 的变化,因为它没有在核心本地缓存中更新。此外, += 运算符不是原子的,因此它可能会从 sum 中读取 20 并将其“2”添加到其中,并将 22 写入 sum,即使另一个线程在读取和写入之间将值更改为 23。要解决这两个问题,您需要使用 AtomicInteger 或 Varhandles (volatile 仅修复可见性问题。这里是有关原子变量的更多信息
推荐阅读
- assembly - 将 PGM 图像文件解析为包含整数和数组的结构 - 如何实现结构?
- rust - 为什么使用带有 #![no_std] 的 rand/rand_core 会导致“重复的语言项”?
- r - 有没有人使用过 FLSSS R 包中的 mmKnapsack 功能,并获得了次优的解决方案?
- sql - 第一个日期和其余日期之间的日期差
- python - Python 3 的 pip 或 pip3
- python - 根据条件连接列的有效方法
- java - 在java中设置写超时HttpsUrlConnection/HttpUrlConnection/UrlConnection
- apache-kafka - 如何使用多个工作人员(相同数量的分区)在同一主题上扩展 kafka 消费者应用程序
- python - KeyError:在 pd.DataFrame.drop() 期间未在 Axis 中找到
- python-3.x - 在 FrozenLake 练习中使用 NN 逼近 q 函数