2 votes

Cette "synchronisation" peut-elle fonctionner ?

1. La façon d'utiliser le terme "synchronisé" est-elle correcte ?
2. Est-ce que le score aléatoire est verrouillé lorsqu'un thread y accède, de sorte que les autres threads ne peuvent pas accéder au score aléatoire ?
3. Si seul changeRandomScore() peut accéder à la variable randomScore et qu'un seul thread peut accéder à changeRandomScore(), alors un seul thread peut accéder à randomScore à la fois. Est-ce correct ?

    import java.*;

public class StudentThread extends Thread {
    int ID;  
    public static int randomScore;

      StudentThread(int i) {
          ID = i;
      }

      public void run() {
          changeRandomScore();

          System.out.println("in run");
      }
public synchronized void changeRandomScore() {
    randomScore = (int) (Math.random()*1000);
}
public static void main(String args[]) throws Exception {
    for (int i = 1;i< 10 ;i++) 
    {
            StudentThread student = new StudentThread(5);

            student.start(); 
            Thread.sleep(100);
            System.out.println(randomScore);
    }             
}  
}

6voto

Paŭlo Ebermann Points 35526

Vous accédez ici à une variable statique à l'intérieur de méthodes synchronisées de différents objets. La synchronisation n'a pas d'effet réel ici, puisque chaque thread utilise son propre moniteur (l'objet thread, dans ce cas). Pour une variable partagée, vous devez également utiliser un moniteur partagé.

Voici une variante qui est synchronisée correctement :

public class StudentThread extends Thread {
  int ID;  
  private static int randomScore;
  private static final Object scoreLock = new Object();

  StudentThread(int i) {
     ID = i;
  }

  public void run() {
     changeRandomScore();

     System.out.println("in run");
  }
  public void changeRandomScore() {
     int tmp = (int) (Math.random()*1000);
     // no need to synchronize the random()-call, too.
     synchronized(scoreLock) {
        randomScore = tmp;
     }
  }
  public static void main(String args[]) throws Exception {
      for (int i = 1;i< 10 ;i++) 
      {
          StudentThread student = new StudentThread(5);

          student.start(); 
          Thread.sleep(100);
          synchronized(scoreLock) {
              System.out.println(randomScore);
          }
      }             
  }  
}

La différence est que nous utilisons maintenant un objet de verrouillage commun ( scoreLock ) et l'utiliser comme paramètre pour les blocs synchronisés, et nous synchronisons également sur cet objet dans la méthode principale de lecture de la partition.

Nous pourrions également déclarer la méthode public static synchronized void changeRandomScore() (ce qui signifie qu'il utilise l'objet de classe comme moniteur) et dans la méthode principale synchronize on StudentThread.class .

Oui, comme d'autres l'ont dit : si vous voulez vous assurer qu'une variable n'est accessible qu'avec une synchronisation appropriée, ne la rendez pas public .

2voto

Chris Thompson Points 18375

Correct, un seul thread pourra accéder à la méthode changeRandomScore() à la fois. Cependant, cela ne signifie pas que plusieurs threads ne pourront pas modifier la variable randomScore simultanément. Elle garantit seulement qu'un seul thread peut exécuter cette méthode à la fois. Cela est d'autant plus vrai que randomScore est public .

Editer Permettez-moi de reformuler et de tenter de répondre à votre "grande question" plutôt qu'à la question explicite que vous avez posée dans votre message. Afin de garantir la synchronisation et le fait qu'un seul thread puisse accéder à randomScore à la fois, vous devez mettre en place une sorte de mécanisme de verrouillage qui contrôle toutes les lectures et écritures de la variable. Pour y parvenir, vous devez définir une interface qui contrôle l'accès à la variable. Vous ne l'avez pas fait dans votre exemple. Vous devez restreindre l'accès à la variable en utilisant l'interface private puis créer des méthodes permettant de manipuler la variable. Il est possible d'y parvenir par la synchronisation des méthodes, mais ce n'est pas toujours l'outil adéquat.

Par exemple, ceci :

public void synchronized myMethod(){
  //code
}

Est équivalent à

public void myMethod(){
  synchronized(this){
    //same code
  }
 }

La synchronisation au niveau de la méthode est donc une synchronisation sur l'instance de l'objet. C'est très bien si vous ne manipulez que des données internes à l'objet, mais cela s'écroule si les variables avec lesquelles vous travaillez ont une portée quelconque en dehors de l'objet (par exemple, dans votre cas, une variable static variable). Dans ce cas, il vous faudrait un autre mécanisme de verrouillage.

1voto

maaartinus Points 12510

Non, vous ne l'utilisez pas correctement. L'écriture est synchronisée, c'est bien, mais cela ne vous rapporte rien du tout. Sans les synchronisations, cela fonctionnerait de la même manière, parce que

  • l'accès à int est de toute façon atomique
  • la lecture n'est pas synchronisée, de sorte que vous pouvez voir des valeurs périmées

Il est préférable de ne jamais exposer un champ nécessitant une synchronisation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X