jvm reordering/visibility effect test

别说谁变了你拦得住时间么 提交于 2020-02-02 03:43:03

问题


While writing some java article I'm trying to reproduce re-ordering in case of unsynchronized object costruction in multithreaded environment. The case when a heavy object is constructed w/o synchonization/volatiles/finals and other threads get access to it right after constructor call. Here is the code I try:

public class ReorderingTest {
    static SomeObject<JPanel>[] sharedArray = new SomeObject[100];

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            String name = "watcher" + i;
            new Thread(new Watcher(name)).start();
            System.out.printf("watcher %s started!%n", name);
        }
    }

    static class Watcher implements Runnable {
        private String name;

        Watcher(String name) {
            this.name = name;
        }

        public void run() {
            while (true) {
                int randomIndex = (int) (Math.random() * sharedArray.length);
                SomeObject<JPanel> item = sharedArray[randomIndex];
                if (item == null) {
                    //System.out.printf("sharedArray[%s]=null%n", randomIndex);
                    double r = 1 + Math.random() * 1000;
                    sharedArray[randomIndex] = new SomeObject<JPanel>(
                            new JPanel(), UUID.randomUUID().toString(), r, (float)r * 33, (long)r);
                } else {
                    //System.out.printf("sharedArray[%s]=<obj>!%n", randomIndex);
                    if (item.value == null ||
                            (item.stringField == null) ||
                            (item.doubleField == 0) ||
                            (item.floatField == 0) ||
                            (item.longField == 0)
                            ) {
                        System.err.printf("watcher %s sees default values: %s!%n", name, item);
                    } else {
                        // fully initialized! run new construction process
                        double r = 1 + Math.random() * 1000;
                        sharedArray[randomIndex] = new SomeObject<JPanel>(
                                new JPanel(), UUID.randomUUID().toString(), r, (float)r * 37, (long)r);

                    }
                }
                /*try {
                    TimeUnit.NANOSECONDS.sleep(randomIndex);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }*/
            }
        }
    }

    static class SomeObject<V> {
        V value;
        String stringField;
        double doubleField;
        float floatField;
        long longField;

        SomeObject(V value, String stringField, double doubleField, float floatField, long longField) {
            this.value = value;
            this.stringField = stringField;
            this.doubleField = doubleField;
            this.floatField = floatField;
            this.longField = longField;
        }

        @Override
        public String toString() {
            return "SomeObject{" +
                    "value=" + value == null ? "null" : "<obj>" +
                    ", stringField='" + stringField + '\'' +
                    ", doubleField=" + doubleField +
                    ", floatField=" + floatField +
                    ", longField=" + longField +
                    '}';
        }
    }
} 

-But no effect so far, I've tried on different 2,4 and 8 core Intel/AMD PCs with windows, ran test for a few hours - no reordering effect - System.err.printf("watcher %s sees ...") - is not called, static sharedArray[randomIndex] reference always contains fully constructed values.

What's wrong? How to reproduce this?


回答1:


Here is a nice article which should show reordering on x86 (quite a feat because the x86 memory model is pretty much "safe"):

http://bartoszmilewski.wordpress.com/2008/11/05/who-ordered-memory-fences-on-an-x86/

Your example will not show reordering. The compiler will not reorder to "store object reference after allocation but before construction" because the constructor could throw and thus the reference would need to be reverted. Some Processors may reorder this, but no intel compatible ones, due to the given guaranties.




回答2:


Re-ordering is not guaranteed. It usually only occurs when the JIT determines there might be a performance gain.

In your case, what you are looking for is not re-ordering but an Object which doesn't appear to have been correctly initialised.

Your objects are highly likely to use a new memory location each time (or at least one which is not in cache) On x86/x64 architectures, I have found that the cache will always be correct the first time it has to load memory when was updated by another thread.




回答3:


re-ordering does not necessarily happen. and when it does, it's hard to observe. you sample size of 100 is too tiny. Try a billion for starters.

Suppose re-ordering happens, at the time of write, reference is assigned first, then fields are populated. Your read process reads the reference first, then reads the fields. So write and read follow the same order, it's almost impossible for read to catch up and get ahead of write.

You can address the issue by

  1. pause in constructor (therefore pause in write)
  2. write and read fields in opposite direction

Still, reordering may not occur and you won't be able to observe it.




回答4:


could you try to declare sharedArray as non-volatile? It seems to me that handing a volatile reference to a correctly constructed object is safe.



来源:https://stackoverflow.com/questions/6264466/jvm-reordering-visibility-effect-test

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!