易失性数组

时间:2017-06-04 01:57:22

标签: java concurrency mutex 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;
        }
    }
}

在我的第一个滤镜算法实现中,我错过volatile变量levellastToEnter,毫不奇怪,程序进入无限循环。添加缺少的volatile后,程序可以按预期结束。

正如我在开始时所说的那样,volatile数组并不意味着数组中的项是易变的,那么为什么程序在添加缺失的volatile之后可以按预期结束?

当我实施另一个互联网算法时,我问自己这个问题,在我添加volatile关键字后,该算法仍然无法正常运行。我必须使用一个技巧(Java volatile array?)来使数组中的项看起来像volatile一样:(下面的代码可以直接粘贴到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;
}

1 个答案:

答案 0 :(得分:1)

Java中的易失性数组不包含易失性元素 - 但如果您通过数组引用(易失性)访问它们,您将获得易失性读取。例如,在上面的代码中:

static volatile int lastToEnter[] = new int[N - 1];

是易失性写入,而

lastToEnter[i] = this.id;

不是。但是,评估数组值 - 例如:

lastToEnter[i] == this.id

易失性读取 - 您首先读取对易失性数组的引用,然后才访问第i个元素以评估其值。

我怀疑这是将数组声明为volatile后执行成功的原因。