Hoe synchroniseer je een statische variabele tussen threads die verschillende instanties van een klasse in Java uitvoeren?

Ik weet dat het gebruik van het sleutelwoord synchronizevoordat een methode synchronisatie naar dat object brengt. Dat wil zeggen dat 2 threads met dezelfde instantie van het object worden gesynchroniseerd.

Omdat de synchronisatie echter op objectniveau plaatsvindt, worden 2 threads met verschillende instanties van het object niet gesynchroniseerd. Als we een statische variabele hebben in een Java-klasse die door de methode wordt aangeroepen, willen we dat deze wordt gesynchroniseerd tussen instanties van de klasse. De twee instanties worden uitgevoerd in 2 verschillende threads.

Kunnen we synchronisatie op de volgende manier bereiken?

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

Is het waar dat, aangezien we een statisch object lockhebben gedefinieerd en we het trefwoord synchronizedvoor dat slot gebruiken, de statische variabele countis nu gesynchroniseerd tussen instanties van klasse Test?


Antwoord 1, autoriteit 100%

Er zijn verschillende manieren om de toegang tot een statische variabele te synchroniseren.

  1. Gebruik een gesynchroniseerde statische methode. Dit wordt gesynchroniseerd op het klasseobject.

    public class Test {
        private static int count = 0;
        public static synchronized void incrementCount() {
            count++;
        }
    } 
    
  2. Expliciet synchroniseren op het klasseobject.

    public class Test {
        private static int count = 0;
        public void incrementCount() {
            synchronized (Test.class) {
                count++;
            }
        }
    } 
    
  3. Synchroniseren op een ander statisch object.

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

Methode 3 is in veel gevallen de beste omdat het lock-object niet buiten je klas wordt weergegeven.


Antwoord 2, autoriteit 32%

Als je gewoon een teller deelt, overweeg dan om een ​​AtomicIntegerof een andere geschikte klasse uit het pakket java.util.concurrent.atomic:

public class Test {
    private final static AtomicInteger count = new AtomicInteger(0); 
    public void foo() {  
        count.incrementAndGet();
    }  
}

Antwoord 3, autoriteit 2%

Ja, het is waar.

Als je twee instanties van je klas maakt

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

Vervolgens synchroniseren t1.foo en t2.foo beide op hetzelfde statische object en blokkeren ze elkaar.


Antwoord 4

We kunnen ook ReentrantLock gebruiken om de synchronisatie voor statische variabelen te bereiken.

public class Test {
    private static int count = 0;
    private static final ReentrantLock reentrantLock = new ReentrantLock(); 
    public void foo() {  
        reentrantLock.lock();
        count = count + 1;
        reentrantLock.unlock();
    }  
}

Antwoord 5

Je kunt je code synchroniseren met de klas. Dat zou het eenvoudigst zijn.

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

Ik hoop dat u dit antwoord nuttig vindt.

Other episodes