配列を宣言した場合、配列への参照はvolatileであることはわかっています。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;
}
}
}
を、私は変数level
とlastToEnter
ためvolatile
を逃し、驚くことではないが、プログラムが無限に入りましたループ。紛失したvolatile
を追加した後、プログラムは期待どおりに終了することができます。
私が最初に言ったように、volatile
配列は、配列内の項目がvolatileであるということを意味しません。
volatile
というキーワードを追加した後でも正しく動作しない別のミューテックスアルゴリズムを実装していたときに、私はこの質問をしました。私は配列は揮発性であることのように見えるでアイテムを作るためにトリック(Java volatile array?)を使用する必要があります - しかし、もし
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;
}
揮発性元素を含まないJavaで
あなたはただ運が良いと思っていますか?コードが正しく1回実行されるか、特定のマシンで常に正しく実行されるという理由だけで、常に正しく動作することが保証されているわけではありません。 Dijkstraのロックコードとの1つの違いは、メインループのvolatile int 'count'に書き込んでいることです。これはループの繰り返しごとにスレッド間の瞬間的な出来事前の関係を作成します(' count'を間違って更新しています'count ++'はアトミックではないので) –
@ErwinBolwidt私はまた、コードが正しく動作するのは単なる運が良いと思っていましたが、コードを複数回実行してこれを確認します。 'volatile'がなければ、' filterLock'は 'volatile'キーワードの状況とは非常に異なる実行の直後に無限ループに入ります。ミューテックスアルゴリズム(正しく実装されている場合)がクリティカルセクションコードを実行しているスレッドが1つしかないことを保証できるため、 'count ++ 'を使用することを意図しています。 – Yon