Java内存模型是否允许重新排序许多原子/易变量的非同步访问?

时间:2014-04-07 21:22:18

标签: java multithreading performance synchronization lock-free

我想知道JMM是否允许实现重新排序对aiada变量的访问,其行为与代码中显示的意图不同。

目的是执行ops的方法是下一个:

  1. 获取易失物品数组的下一个索引
  2. 在新获得的索引中写入一个数字
  3. 执行一个自旋锁,等待确保数组的旧索引得到它的值
  4. 将数组的总和从第一个索引打印到当前获得的数组。
  5. 索引达到1000后会发生什么对我来说并不重要。我实际上想要将数组用作环,但如果这个问题得到解答,我将能够弄清楚如何做到这一点。

    基本上我想避免锁定并依赖原子和无锁对象。但我不知道在这种特殊情况下我是否还需要隐式同步。

    AtomicInteger ai = new AtomicInteger(0);
    // let's say all values are null by default
    AtomicDoubleArray ada = new AtomicDoubleArray(1000); 
    int rn = 4; // dice rolled...
    
    void perfomOps(AtomicInteger ai, AtomicDoubleArray ada) {
       int i = ai.getAndIncrement();
       ada.set(i, rn); 
       spinlock(ada, i);
       printSum(ada, i);
    }
    
    void spinlock(AtomicDoubleArray ada, int idx) {
    // spinlock in case the other threads couln't write to older indexes yet
       if (idx > 0)
          for (int c = 0;c < idx; c++) 
             while (i = ada.get(c) == null);
    }
    
    void printSum(AtomicDoubleArray ada, int idx) {
       double sum = 0;
       for (int i = 0;i < idx; i++)
          sum = sum + ada.get(i);
       Sytem.out.println(sum);
    }
    
    // thread 1
    perfomOps(ai, ada); // lets say we get 4 printed
    
    // thread 2
    perfomOps(ai, ada); // lets say we get 8 printed
    
    // thread 3
    perfomOps(ai, ada); // lets say we get 12 printed
    

    其他线程将继续这样做,可能会发生打印顺序不符合预期,如8,12和4。但假设下一个线程进来,那么它将看到正确的值并正确打印16

    所有这些花哨的东西都是为了避免显式锁定以测量哪一个表现更好,无锁版本或同步版本

1 个答案:

答案 0 :(得分:3)

Java内存模型最重要的规则是(§17.4.5):

  

当且仅当所有顺序一致的执行没有数据争用时,程序才能正确同步。如果程序正确同步,则程序的所有执行都将显示为顺序一致(第17.4.3节)。

如果所有共享变量都是 volatile atomic ,那么就没有数据竞争。这意味着sequential consistency得到保证。这意味着,在程序的行为中不会出现重新排序。