Sur Intel des nations unies a soutenu lecture volatile est assez bon marché. Si nous considérons le cas simple suivant:
public static long l;
public static void run() {
if (l == -1)
System.exit(-1);
if (l == -2)
System.exit(-1);
}
À l'aide de Java 7 capacité d'assemblage d'impression de code à l'exécution de la méthode ressemble à quelque chose comme:
# {method} 'run2' '()V' in 'Test2'
# [sp+0x10] (sp of caller)
0xb396ce80: mov %eax,-0x3000(%esp)
0xb396ce87: push %ebp
0xb396ce88: sub $0x8,%esp ;*synchronization entry
; - Test2::run2@-1 (line 33)
0xb396ce8e: mov $0xffffffff,%ecx
0xb396ce93: mov $0xffffffff,%ebx
0xb396ce98: mov $0x6fa2b2f0,%esi ; {oop('Test2')}
0xb396ce9d: mov 0x150(%esi),%ebp
0xb396cea3: mov 0x154(%esi),%edi ;*getstatic l
; - Test2::run@0 (line 33)
0xb396cea9: cmp %ecx,%ebp
0xb396ceab: jne 0xb396ceaf
0xb396cead: cmp %ebx,%edi
0xb396ceaf: je 0xb396cece ;*getstatic l
; - Test2::run@14 (line 37)
0xb396ceb1: mov $0xfffffffe,%ecx
0xb396ceb6: mov $0xffffffff,%ebx
0xb396cebb: cmp %ecx,%ebp
0xb396cebd: jne 0xb396cec1
0xb396cebf: cmp %ebx,%edi
0xb396cec1: je 0xb396ceeb ;*return
; - Test2::run@28 (line 40)
0xb396cec3: add $0x8,%esp
0xb396cec6: pop %ebp
0xb396cec7: test %eax,0xb7732000 ; {poll_return}
;... lines removed
Si vous regardez les 2 références à getstatic, la première implique une charge de la mémoire, le deuxième ignore la charge que la valeur est réutilisé par le registre(s), il est déjà chargé dans la (longue est de 64 bits et sur mon 32 bits portable, il utilise 2 registres).
Si nous faisons le l variable volatile de l'assemblage qui en résulte est différent.
# {method} 'run2' '()V' in 'Test2'
# [sp+0x10] (sp of caller)
0xb3ab9340: mov %eax,-0x3000(%esp)
0xb3ab9347: push %ebp
0xb3ab9348: sub $0x8,%esp ;*synchronization entry
; - Test2::run2@-1 (line 32)
0xb3ab934e: mov $0xffffffff,%ecx
0xb3ab9353: mov $0xffffffff,%ebx
0xb3ab9358: mov $0x150,%ebp
0xb3ab935d: movsd 0x6fb7b2f0(%ebp),%xmm0 ; {oop('Test2')}
0xb3ab9365: movd %xmm0,%eax
0xb3ab9369: psrlq $0x20,%xmm0
0xb3ab936e: movd %xmm0,%edx ;*getstatic l
; - Test2::run@0 (line 32)
0xb3ab9372: cmp %ecx,%eax
0xb3ab9374: jne 0xb3ab9378
0xb3ab9376: cmp %ebx,%edx
0xb3ab9378: je 0xb3ab93ac
0xb3ab937a: mov $0xfffffffe,%ecx
0xb3ab937f: mov $0xffffffff,%ebx
0xb3ab9384: movsd 0x6fb7b2f0(%ebp),%xmm0 ; {oop('Test2')}
0xb3ab938c: movd %xmm0,%ebp
0xb3ab9390: psrlq $0x20,%xmm0
0xb3ab9395: movd %xmm0,%edi ;*getstatic l
; - Test2::run@14 (line 36)
0xb3ab9399: cmp %ecx,%ebp
0xb3ab939b: jne 0xb3ab939f
0xb3ab939d: cmp %ebx,%edi
0xb3ab939f: je 0xb3ab93ba ;*return
;... lines removed
Dans ce cas, les deux de la getstatic références à la variable l implique une charge à partir de la mémoire, c'est à dire la valeur ne peut pas être conservés dans un registre au travers de multiples volatils lit. Pour s'assurer qu'il n'y est atomique lire la valeur est lue depuis la mémoire principale dans un registre MMX movsd 0x6fb7b2f0(%ebp),%xmm0
faire l'opération de lecture d'une seule instruction (à partir de l'exemple précédent, nous avons vu que 64bit valeur aurait normalement besoin de deux 32bit lit sur un système 32 bits).
Si le coût global de la volatilité et de la lecture à peu près l'équivalent de la charge de la mémoire et peuvent être aussi bas que un cache L1 de l'accès. Toutefois, si un autre noyau est écrit à la volatilité de la variable, le cache-ligne sera invalidé nécessitant une mémoire principale ou peut-être un cache L3 de l'accès. Le coût réel dépendra fortement de l'architecture du PROCESSEUR. Même entre Intel et AMD, les protocoles de cohérence de cache sont différents.