Strange behavior of a volatile array

I know this means that the reference to the array is unstable and not the elements in the array if you are declaring an array volatile

.

I am learning mutex algorithm, so I write test code:

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;
        }
    }
}

      

In my first implementation of the filter algorithm, I skipped volatile

for variables level

and lastToEnter

, not surprisingly, the program went into an infinite loop. After I added the missing one volatile

, the program might end as expected.

As I said at the beginning, an array volatile

does not mean that the elements in the array are unstable, so why could the program end as expected after I added the missing one volatile

?

I asked myself this question when I implemented another mutex algorithm that still doesn't work correctly after adding the keyword volatile

. I need to use the ( Java volatile array? ) Trick to make the elements in the array appear volatile: (the code below can be inserted directly into the class 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;
}

      

+3


source to share


1 answer


Volatile arrays in Java do not contain volatile elements, but if you access them via an array reference (which is volatile), you get an unstable read. For example, in the above code:

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

      

is volatile write, whereas

lastToEnter[i] = this.id;

      



not. however, evaluating the value of an array - for example:

lastToEnter[i] == this.id

      

is volatile reading - first you read a reference to an array, which is volatile, and only then access the i-th element to evaluate its value.

I suspect this is the reason why your execution succeeds as soon as the array is declared volatile.

+1


source







All Articles