我知道这意味着如果你声明一个数组volatile
,那么对数组的引用不是数组中的项。挥发性阵列的奇怪行为
我学习互斥算法,所以我写了一些测试代码:
public class MutualExclusion {
static final int N = 10;
static final int M = 100000;
volatile static int count = 0;
public static void main(String[] args) {
Thread[] threads = new Thread[N];
for (int i = 0; i < N; i++) {
Thread t = new Worker(i);
threads[i] = t;
t.start();
}
for (Thread t: threads) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count != N * M) {
System.out.println("count (" + count + ") != N * M (" + String.valueOf(N * M) + ")");
}
}
static class Worker extends Thread {
int id;
Worker(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < M; i++) {
this.lock();
// critical section
count++;
if (i % 1000 == 0) {
System.out.println(this.getName() + ": " + count);
}
this.unlock();
}
}
void lock() {
filterLock();
}
void unlock() {
filterUnlock();
}
static volatile int level[] = new int[N];
static volatile int lastToEnter[] = new int[N - 1];
void filterLock() {
for (int i = 0; i < (N - 1); i++) {
level[this.id] = i;
lastToEnter[i] = this.id;
outer:
while (lastToEnter[i] == this.id) {
for (int k = 0; k < N; k++) {
if (k != this.id && level[k] >= i) {
continue outer;
}
}
break;
}
}
}
void filterUnlock() {
level[this.id] = -1;
}
}
}
在我的第一个实施滤波算法,我错过了volatile
可变level
和lastToEnter
,这并不奇怪,程序进入一个无限循环。在我添加了缺失的volatile
后,该程序可以按预期结束。
正如我在开始时所说的,volatile
数组并不意味着数组中的项是易失性的,那么为什么在添加缺少的volatile
后程序结束了预期?
当我添加volatile
关键字后,我在执行另一个互斥算法时仍然无法正确运行,我问自己这个问题。我有一个小窍门(Java volatile array?),使项目在阵列看起来是挥发性的:(下面的代码可以被粘贴到直接Worker
类)
volatile static boolean[] b = new boolean[N];
volatile static boolean[] c = new boolean[N];
volatile static int k = 0;
void dijkstraLock() {
b[this.id] = false;
outer:
for (;;) {
if (k == this.id) {
c[this.id] = false;
c = c; // IMPORTANT! the trick
for (int i = 0; i < N; i++) {
if (i != this.id && !c[i]) {
continue outer;
}
}
break;
} else {
c[this.id] = true;
if (b[k]) {
k = this.id;
}
}
}
}
void dijkstraUnlock() {
b[this.id] = true;
c[this.id] = true;
}
你认为你可以幸运吗?仅仅因为您的代码一次正确运行,或者即使它在您的特定机器上始终正常运行,也并不意味着它始终能够正常运行。与Dijkstra锁定代码的一个区别是,您正在写入主循环中的volatile int'count',这会在每次循环迭代时在线程之间创建一个瞬间发生 - 之前的关系(请注意,您正在更新'count' ,因为'count ++'不是原子的) –
@ErwinBolwidt我也认为代码正确运行可能是幸运的,但是,我多次运行代码以确认这一点。如果没有volatile,filterLock会在执行后很快进入死循环,这与volatile关键字的情况非常不同。我打算使用'count ++',因为互斥算法(如果实现正确)可以确保只有一个线程正在执行关键部分代码。 – Yon