0

При выполнении следующего фрагмента кода я вижу, что результаты становятся все правильно и однозначно порядковым однако они печатаются в порядке (как показано ниже):Действительно ли атомизация в Java гарантирует заказ или только уникальность?

import java.util.concurrent.atomic.AtomicInteger; 

public class Atomics { 

    private AtomicInteger index = new AtomicInteger(0); 

    public static void main(String [] args) { 
     new Atomics().updateIndexViaCAS(); 
    } 

    private void updateIndexViaCAS() { 

     Runnable target =() -> { 
      for(int i = 0; i<10;i++) { 
       cas: 
       while (true) { 
        int oldValue = index.get(); 
        int newValue = oldValue + 1; 
        if(index.compareAndSet(oldValue, newValue)) { 
         System.out.println(Thread.currentThread() + ": "+newValue); //order is not guaranteed? 
         break cas; 
        } 
       } 
      } 
     }; 

     /*Runnable target =() -> { 
      for (int i = 0; i < 10; i++) { 
       int oldValue = index.get(); 
       int newValue = oldValue + 1; 
       do { 
        oldValue = index.get(); 
       } while (!index.compareAndSet(oldValue, newValue)); 
       System.out.println(Thread.currentThread() + ": "+newValue); 
      } 
     };*/ 

     for(int t=0; t<2;t++) { 
      Thread th = new Thread(target); 
      th.start(); 
     } 


    } 
} 

Sample Результаты:

Thread[Thread-0,5,main]: 1 
Thread[Thread-0,5,main]: 3 
Thread[Thread-0,5,main]: 4 
Thread[Thread-0,5,main]: 5 
Thread[Thread-0,5,main]: 6 
Thread[Thread-1,5,main]: 2 <-- out of order 
Thread[Thread-0,5,main]: 7 
Thread[Thread-0,5,main]: 9 
Thread[Thread-0,5,main]: 10 
Thread[Thread-0,5,main]: 11 
Thread[Thread-0,5,main]: 12 
Thread[Thread-1,5,main]: 8 <-- out of order 
Thread[Thread-1,5,main]: 13 
Thread[Thread-1,5,main]: 14 
Thread[Thread-1,5,main]: 15 
Thread[Thread-1,5,main]: 16 
Thread[Thread-1,5,main]: 17 
Thread[Thread-1,5,main]: 18 
Thread[Thread-1,5,main]: 19 
Thread[Thread-1,5,main]: 20 

ли потому что:

  1. С кодом что-то не так (и если да, то как его исправить для обеспечения порядка)?

  2. Является ли это правильным поведением атомистики, потому что по дизайну они не гарантируют выполнение заказа, а только гарантируют бесконтактный параллелизм?

  3. Что-то еще на работе здесь?

TIA.

Чтобы устранить мое замешательство с комментариями ниже - зачем мне Atomic в первую очередь, если мне все еще нужно использовать синхронизацию, чтобы посмотреть, что происходит, как показано ниже?

Runnable target =() -> { 
    for (int i = 0; i < 10; i++) { 
     cas: while (true) { 
      synchronized (mutex) { 
       int oldValue = index.get(); 
       int newValue = oldValue + 1; 
       if (index.compareAndSet(oldValue, newValue)) { 
        System.out.println(Thread.currentThread() + ": " 
          + newValue); // order is not guaranteed? 
        break cas; 
       } 
      } 
     } 
    } 
}; 
+7

Порядок, в котором 'index' принимает свои значения, необязательно является порядком, в котором происходят вызовы' println'. 'CompareAndSet' является атомарным; 'compareAndSet'-and-println - нет. – user2357112

+0

Это # 2. Атомные переменные обеспечивают атомарность обновлений и видимость обновлений. Они не имеют никакого отношения к заказу. –

+0

@ 4castle: значит, это означает, что атомный CAS действительно ничего не покупает, так как мне еще нужно синхронизировать, чтобы посмотреть, что мне интересно видеть через 'println'? Или что? Примеры кода оцениваются. –

ответ

1

Нет гарантии, что ваш код чередуется. В вашем случае, я думаю, что путаница в том, что цикл не выполняется как единое целое, но может чередовать каким-либо образом. Подумайте о завершении нитки 1 перед выполнением System.out.println(Thread.currentThread() + ": " + newValue), где newValue был увеличен с 0 до 1, так что пока ничего не напечатан. Затем поток 2 может увеличиваться от 1 до 2 и распечатывать его outpout перед другим потоком. Это приведет к тому, что большее число будет напечатано первым.

Кроме того, помните, что System.out.println синхронизируется на System.out. Вот почему вы всегда наблюдаете куски отпечатков в правильном порядке. Один поток, вероятно, обнаруживает, что System.out заблокирован и временно приостанавливает свою деятельность, прежде чем возобновлять свою деятельность.