web-dev-qa-db-fra.com

Que veut dire "atomique" dans la programmation?

Dans le livre Effective Java, il est indiqué:

La spécification de langue garantit que la lecture ou l'écriture d'une variable est atomique, sauf si la variable est de type long ou double [JLS, 17.4.7].

Que signifie "atomique" dans le contexte de Java programmation, ou de la programmation en général?

239
James

Voici un exemple, car un exemple est souvent plus clair qu'une longue explication. Supposons que foo soit une variable de type long. L'opération suivante n'est pas une opération atomique:

foo = 65465498L;

En effet, la variable est écrite en utilisant deux opérations distinctes: une qui écrit les 32 premiers bits et une seconde qui écrit les 32 derniers bits. Cela signifie qu'un autre thread pourrait lire la valeur de foo et voir l'état intermédiaire.

Rendre l’opération atomique consiste à utiliser des mécanismes de synchronisation afin de s’assurer que l’opération est vue, à partir de tout autre thread, comme une opération unique, atomique (c’est-à-dire non divisible en plusieurs parties). Cela signifie que tout autre thread, une fois l'opération rendue atomique, verra la valeur de foo avant l'affectation ou après l'affectation. Mais jamais la valeur intermédiaire.

Un moyen simple de le faire est de faire le variable volatile :

private volatile long foo;

Ou pour synchroniser chaque accès à la variable:

public synchronized void setFoo(long value) {
    this.foo = value;
}

public synchronized long getFoo() {
    return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized

Ou pour le remplacer par AtomicLong :

private AtomicLong foo;
335
JB Nizet

"Opération atomique" signifie une opération qui semble être instantanée du point de vue de tous les autres threads. Vous n'avez pas à vous soucier d'une opération en partie complète lorsque la garantie s'applique.

51
H2ONaCl

C'est quelque chose qui "semble apparaître instantanément au reste du système" et relève de la catégorisation de linéarisation dans les processus informatiques. Pour citer cet article lié plus loin:

Atomicity est une garantie d'isolement des processus concurrents. De plus, les opérations atomiques ont généralement une définition de succès ou d'échec - elles changent avec succès l'état du système ou n'ont aucun effet apparent.

Ainsi, par exemple, dans le contexte d’un système de base de données, il est possible d’avoir des "commits atomiques", ce qui signifie que vous pouvez envoyer un ensemble de modifications à une base de données relationnelle et que ces modifications seront soit toutes soumises, soit aucune de ces modifications. En cas d’échec, les données ne sont donc pas corrompues et il en résulte des verrous et/ou des files d’attente, la prochaine opération sera une écriture différente ou une lecture, mais seulement après le fait. Dans le contexte des variables et du threading, c'est à peu près la même chose, appliquée à la mémoire.

Votre citation souligne que ce comportement et non ne doit pas être attendu dans tous les cas.

22
Grant Thomas

Je viens de trouver un message Atomic vs. Non-Atomic Operations m'a été très utile.

"Une opération agissant sur la mémoire partagée est atomique si elle s’effectue en une seule étape par rapport aux autres threads.

Lorsqu'un stockage atomique est effectué sur une mémoire partagée, aucun autre thread ne peut observer la modification à moitié terminée.

Lorsqu'une charge atomique est effectuée sur une variable partagée, elle lit la valeur entière telle qu'elle est apparue à un moment donné. "

12
Kurt Zhong

Si vous avez plusieurs threads exécutant les méthodes m1 et m2 dans le code ci-dessous:

class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}

vous avez la garantie que tout thread appelant m2 lira 0 ou 5.

Par contre, avec ce code (où i est un long):

class SomeClass {
    private long i = 0;

    public void m1() { i = 1234567890L; }
    public long m2() { return i; }
}

un thread appelant m2 pourrait indiquer 0, 1234567890L ou une autre valeur aléatoire, car l'instruction i = 1234567890L n'est pas garantie d'être atomique pour un long (une machine virtuelle pourrait écrire les 32 premiers bits et les 32 derniers bits de deux opérations et un thread pourrait observer i entre les deux).

12
assylias