1
votes

comment fonctionne le bloc synchronisé?

J'apprends le multi-threading. J'ai écrit un programme utilisant la synchronisation pour imprimer la table de 10 et 5 en utilisant deux threads. Alors que la méthode synchronisée me donne le résultat attendu, le bloc synchronisé ne l'est pas. Qu'est-ce que je fais mal?

public class SynchronizationDemo {

public static void main(String[] args) {
    Thread1 t=new Thread1(10);
    Thread1 t1=new Thread1(5);
    Thread thread1=new Thread(t);
    Thread thread2=new Thread(t1);
    thread1.start();
    thread2.start();
}
//synchronized method
/*public static synchronized void printTable(int num) {
    for (int i = 1; i <= 10; i++) {
        System.out.println(num*i);
        try {
            Thread.sleep(1000);
        }catch(InterruptedException ie){
            ie.printStackTrace();
        }
    }
}*/
//synchronized block
public void printTable(int num)
{
    synchronized(this){
        for (int i = 1; i <= 10; i++) {
            System.out.println(num*i);
            try {
                Thread.sleep(1000);
            }catch(InterruptedException ie){
                ie.printStackTrace();
            }
        }
     }
   }
 }

class Thread1 implements Runnable{
    int num;
    Thread1(int num){
        this.num=num;
    }
    @Override
    public void run() {
        new SynchronizationDemo().printTable(num);
    }
}

Sortie du code: dix 5 dix 20 30 15 20 40 25 50 60 30 70 35 40 80 90 45 100 50

Résultat attendu: dix 20 30 40 50 60 70 80 90 100 5 dix 15 20 25 30 35 40 45 50


4 commentaires

Sans code complet (où se trouve Thread1 ?), Il est difficile de le savoir. Je suppose que synchronize (this) se synchronise sur deux objets distincts et ne bloque donc aucun des threads. Alors que la méthode statique se synchronise évidemment sur un objet commun qui bloquera l'autre thread.


Le code est complet. La classe Thread1 est définie. Merci. J'ai la réponse.


passez par ceci: docs.oracle.com/javase/tutorial/essential/ concurrence /… pour avoir une bonne compréhension de la concurrence.


Bien que les gens aient répondu à votre question, je suggérerais de choisir une tâche qui peut être traitée en parallèle. Votre sortie attendue est le traitement en série.


4 Réponses :


0
votes

La différence est que vous avez également changé la méthode pour qu'elle ne soit plus static.

synchronized(SynchronizationDemo.class){
}

Ceci verrouille sur la classe, pas sur une seule instance .

Le bloc synchronisé équivalent serait

public static synchronized void printTable(int num) { }

Donc même si vous avez deux instances, elles utilisent toujours le même verrou (car elles sont toutes les deux de la même classe), alors qu'un synchronisé (this) se verrouille sur deux objets indépendants.


0 commentaires

1
votes

Vous utilisez le mot-clé synchronized dans deux contextes différents.

    La méthode
  1. statique synchronisée attend et obtient un verrou au niveau de la classe SynchronizationDemo et il n'y a qu'un seul verrou pour cette classe. Toutes les instances de cette classe devront donc attendre ce verrou dans une séquence.

  2. synchronized (this) bloc (ou même une méthode) attend et obtient un verrou d'objets de la classe SynchronizationDemo et il y a un verrou pour chaque objet. Comme chaque méthode run () crée sa propre instance new SynchronizationDemo () , cette méthode n'a pas besoin d'attendre que les autres méthodes soient terminées.

Essayez de changer votre classe Thread1 en passant un objet.

public static void main(String[] args) {
    SynchronizationDemo demo = new SynchronizationDemo();
    Thread1 t=new Thread1(demo, 10);
    Thread1 t1=new Thread1(demo, 5);
    Thread thread1=new Thread(t);
    Thread thread2=new Thread(t1);
    thread1.start();
    thread2.start();
}

Vous pouvez maintenant transmettre le même objet de la classe SynchronizationDemo aux deux threads comme ci-dessous.

class Thread1 implements Runnable{
    SynchronizationDemo demo;
    int num;

    Thread1(SynchronizationDemo demo, int num){
        this.demo = demo;
        this.num = num;
    }

    @Override
    public void run() {
        demo.printTable(num);
    }
}


0 commentaires

4
votes

La principale différence entre les deux approches réside dans un petit mais important détail.

  • Votre bloc synchronisé se synchronise sur ce.

  • Votre méthode synchronisée (la méthode commentée!) est une méthode statique . Cela signifie qu'il se synchronise sur l'objet de classe SynchronizationDemo !!

Mais cela n'explique pas tout. L'autre chose est la façon dont vous appelez la méthode.

    new SynchronizationDemo().printTable(num);

Vous créez une nouvelle instance, puis vous appelez la méthode dessus.

  • Lorsque vous appelez la méthode statique, l'instance que vous utilisez ne fait aucune différence car vous synchronisez sur l'objet Class .

  • Lorsque vous appelez la méthode d'instance, les instances sont différentes, et donc il n'y a aucune exclusion mutuelle. Vous n'obtenez une exclusion mutuelle et une bonne synchronisation que lorsque les deux threads se synchronisent sur le même objet.


1 commentaires

Oui, je l'ai remarqué lorsque @markspace l'a indiqué. Merci beaucoup de l'expliquer



0
votes

Vous créez une nouvelle instance de l'objet de SynchronizationDemo dans la méthode de thread run () .

public static synchronized  void printTable(int num){
     //do sth.
}

Ainsi, chaque thread a un nouvel objet. Ainsi, dans SynchronizationDemo.class , les blocs synchronisés sont inutiles si deux ou plusieurs threads n'accèdent pas au même objet. À cause de cela, les threads fonctionnent avec un objet différent et chaque thread imprime son numéro.

Exécutez votre code 2 fois ou plus, vous pouvez voir la sortie différente, si thread1 fonctionne plus tôt que thread2 ou pas.

Vous devez utiliser le mot-clé static synchronized avec la méthode printTable ;

@Override
public void run() {
    new SynchronizationDemo().printTable(num);
}


0 commentaires