web-dev-qa-db-fra.com

Apprentissage de Java, utilisation de mot-clé synchronisé

donc je testais avec le mot clé synchronized. Voici un exemple que j'ai essayé:

public class MyTest {
    static int i = 0;
    public static void main(String[] args) {
        new Thread(t1).start();
        new Thread(t2).start();
    }

    private static void countMe(String name){
        i++;
        System.out.println("Current Counter is: " + i + ", updated by: " + name);
    }

    private static Runnable t1 = new Runnable() {
        public void run() {
            try{
                for(int i=0; i<5; i++){
                    countMe("t1");
                }
            } catch (Exception e){}

        }
    };

    private static Runnable t2 = new Runnable() {
        public void run() {
            try{
                for(int i=0; i<5; i++){
                    countMe("t2");
                }
            } catch (Exception e){}
       }
    };
}  

Lorsque je l'exécute, la sortie de l'appel de la méthode countMe() à partir de deux threads génère cette sortie:

Current Counter is: 1
Current Counter is: 2
Current Counter is: 4
Current Counter is: 5
Current Counter is: 6
Current Counter is: 7
Current Counter is: 3
Current Counter is: 8
Current Counter is: 9
Current Counter is: 10  

Et quand je change la méthode countMe() en:

private synchronized static void countMe(){
        i++;
        System.out.println("Current Counter is: " + i);
}  

J'obtiens cette sortie:

Current Counter is: 1
Current Counter is: 2
Current Counter is: 3
Current Counter is: 4
Current Counter is: 5
Current Counter is: 6
Current Counter is: 7
Current Counter is: 8
Current Counter is: 9
Current Counter is: 10  

Bien que cela me permette de comprendre clairement le but de synchronized, je veux savoir s'il existe également une autre raison, que nous pouvons utiliser synchronized. Ou ce que j'ai fait ici, est-ce la seule raison pour laquelle nous avons besoin de ce mot-clé synchronized?

Merci.

EDIT: Une autre chose avec laquelle je suis confus est que dans la première sortie, pourquoi le compteur est passé à 3 après 7. Cela me semble un peu impossible, mais des résultats similaires se produisent chaque fois que j'essaye, est-ce Ordinaire?

28
911TurboS

Deux choses:

Premièrement, il n'est pas possible que deux invocations de méthodes synchronisées sur le même objet s'entrelacent. Lorsqu'un thread exécute une méthode synchronisée pour un objet, tous les autres threads qui appellent des méthodes synchronisées pour le même bloc d'objet (suspendent l'exécution) jusqu'à ce que le premier thread soit terminé avec l'objet.

Deuxièmement, lorsqu'une méthode synchronisée se termine, elle établit automatiquement une relation passe-avant avec tout appel ultérieur d'une méthode synchronisée pour le même objet. Cela garantit que les modifications de l'état de l'objet sont visibles pour tous les threads.

Les méthodes synchronisées permettent une stratégie simple pour éviter les interférences de threads et les erreurs de cohérence de la mémoire: si un objet est visible par plusieurs threads, toutes les lectures ou écritures sur les variables de cet objet sont effectuées via des méthodes synchronisées. (Une exception importante: les champs finaux, qui ne peuvent pas être modifiés après la construction de l'objet, peuvent être lus en toute sécurité via des méthodes non synchronisées, une fois l'objet construit).

source: http://docs.Oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

26
vulkanino

Vulkanino a donné une bonne réponse à votre question principale, donc je ne répondrai à votre question que sur l'impression 3 après 7.

Le 3 peut imprimer après le 7 car il y a en fait beaucoup plus de code octet dans vos instructions que Java code.

Je développerai cela.

Tu appelles

System.out.println("Current Counter is: " + i);

et cela se produit dans une ligne de Java, mais ce qui se passe vraiment, c'est qu'une chaîne est créée, puis cette chaîne est passée à println. La méthode println elle-même doit faire un peu de traitement avant écrit en fait la ligne sur la console.

Conceptuellement, quelque chose comme ce qui suit se produit.

String printlnString = "Current Counter is: 3"
--> maybe the other thread executes here
System.out.println(printlnString);
--> or maybe the other thread executes here
i is now equal to 7 and the console has "Current Counter is: 7"
println writes "Current Counter is: 3" to console
11
David V