web-dev-qa-db-fra.com

Comment synchroniser une variable statique entre les threads exécutant différentes instances d'une classe en Java?

Je sais que l'utilisation du mot clé synchronize avant qu'une méthode amène la synchronisation à cet objet. C'est-à-dire que 2 threads exécutant la même instance de l'objet seront synchronisés.

Cependant, étant donné que la synchronisation est au niveau de l'objet, 2 threads exécutant différentes instances de l'objet ne seront pas synchronisés. Si nous avons une variable statique dans une classe Java appelée par la méthode, nous aimerions qu'elle soit synchronisée entre les instances de la classe. Les deux instances s'exécutent dans 2 threads différents.

Pouvons-nous réaliser la synchronisation de la manière suivante?

public class Test  
{  
   private static int count = 0;  
   private static final Object lock= new Object();    
   public synchronized void foo() 
  {  
      synchronized(lock)
     {  
         count++;  
     }  
  }  
}

Est-il vrai que puisque nous avons défini un objet lock qui est statique et que nous utilisons le mot clé synchronized pour ce verrou, la variable statique count est maintenant synchronisée entre les instances de classe Test?

118
Anonymous

Il existe plusieurs façons de synchroniser l'accès à une variable statique.

  1. Utilisez une méthode statique synchronisée. Cela se synchronise sur l'objet de classe.

    public class Test {
        private static int count = 0;
    
        public static synchronized void incrementCount() {
            count++;
        }
    } 
    
  2. Synchroniser explicitement sur l'objet de classe.

    public class Test {
        private static int count = 0;
    
        public void incrementCount() {
            synchronized (Test.class) {
                count++;
            }
        }
    } 
    
  3. Synchroniser sur un autre objet statique.

    public class Test {
        private static int count = 0;
        private static final Object countLock = new Object();
    
        public void incrementCount() {
            synchronized (countLock) {
                count++;
            }
        }
    } 
    

La méthode 3 est la meilleure dans de nombreux cas, car l'objet de verrouillage n'est pas exposé en dehors de votre classe.

188
Darron

Si vous partagez simplement un compteur, envisagez d'utiliser AtomicInteger ou une autre classe appropriée du package Java.util.concurrent.atomic:

public class Test {

    private final static AtomicInteger count = new AtomicInteger(0); 

    public void foo() {  
        count.incrementAndGet();
    }  
}
63
Kevin

Oui c'est vrai.

Si vous créez deux instances de votre classe

Test t1 = new Test();
Test t2 = new Test();

Ensuite, t1.foo et t2.foo se synchronisent sur le même objet statique et se bloquent donc l'un l'autre.

4
richs