Question

Quelqu'un peut-il me dire l'avantage de la méthode synchronisée sur le bloc synchronisé avec un exemple?

Était-ce utile?

La solution

  

Quelqu'un peut-il me dire l'avantage de la méthode synchronisée sur le bloc synchronisé avec un exemple? Merci.

Il n'y a pas un net avantage d'utiliser la méthode synchronisée sur le bloc.

Peut-être le seul (mais je ne dirais pas un avantage) est que vous ne avez pas besoin d'inclure la référence d'objet this.

Méthode:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

Bloc:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}

Voir? Aucun avantage du tout.

blocs faire ont des avantages par rapport aux méthodes bien, la plupart du temps en flexibilité parce que vous pouvez utiliser un autre objet comme verrou alors que la synchronisation de la méthode bloquerait l'objet entier.

Comparer:

// locks the whole object
... 
private synchronized void someInputRelatedWork() {
    ... 
}
private synchronized void someOutputRelatedWork() {
    ... 
}

vs.

// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();

private void someInputRelatedWork() {
    synchronized(inputLock) { 
        ... 
    } 
}
private void someOutputRelatedWork() {
    synchronized(outputLock) { 
        ... 
    }
}

De plus, si la méthode grandit, vous pouvez toujours garder la section synchronisée séparée:

 private void method() {
     ... code here
     ... code here
     ... code here
    synchronized( lock ) { 
        ... very few lines of code here
    }
     ... code here
     ... code here
     ... code here
     ... code here
}

Autres conseils

La seule différence est qu'un bloc synchronisé peut choisir quel objet il se synchronise sur. Une méthode synchronisée ne peut utiliser 'this' (ou l'instance de classe correspondant à une méthode de classe synchronisé). Par exemple, ceux-ci sont sémantiquement équivalentes:

synchronized void foo() {
  ...
}

void foo() {
    synchronized (this) {
      ...
    }
}

Ce dernier est plus souple car il peut concourir pour la serrure associée de any objet, souvent une variable membre. Il est également plus précis parce que vous pourriez avoir du code concurrent exécuter avant et après le bloc, mais toujours dans la méthode. Bien sûr, vous pouvez tout aussi facilement utiliser une méthode synchronisée par refactorisation du code simultané dans les méthodes non-synchronisés. Utilisez selon rend le code plus compréhensible.

méthode synchronisée

Avantages:

  • Votre IDE peut indiquer les méthodes synchronisées.
  • La syntaxe est plus compacte.
  • Forces de diviser les blocs synchronisés à des procédés distincts.

Moins:

  • Synchronise à cela et permet aux étrangers de se synchroniser aussi.
  • Il est plus difficile de se déplacer en dehors du bloc de code synchronisé.

bloc synchronisé

Avantages:

  • Permet d'utiliser une variable privée pour la serrure et ainsi forcer la serrure à rester à l'intérieur de la classe.
  • blocs synchronisés peuvent être trouvés par des références à la recherche de la variable.

Moins:

  • La syntaxe est plus compliquée et donc rend le code plus difficile à lire.

Personnellement, je préfère utiliser des méthodes synchronisées avec les classes axées uniquement à la chose synchronisation besoin. Une telle classe doit être aussi faible que possible et il devrait donc être facile de revoir la synchronisation. D'autres ne devraient pas avoir besoin de se soucier de la synchronisation.

La principale différence est que si vous utilisez un bloc synchronisé vous pouvez verrouiller sur un objet autre que ce qui permet d'être beaucoup plus flexible.

Supposons que vous avez une file d'attente de messages et plusieurs producteurs de message et les consommateurs. Nous ne voulons pas que les producteurs d'interférer les uns avec les autres, mais les consommateurs devraient pouvoir récupérer des messages sans avoir à attendre pour les producteurs. Alors que nous venons de créer un objet

Object writeLock = new Object();

Et à partir de maintenant chaque fois qu'un producteurs veut ajouter un nouveau message que nous fermons simplement sur ce point:

synchronized(writeLock){
  // do something
}

Alors les consommateurs peuvent encore lire, et les producteurs seront verrouillés.

méthode synchronisée

méthodes Synchronisé ont deux effets.
D'abord, quand un fil exécute une méthode synchronisée pour un objet, tous les autres fils qui font appel à des méthodes synchronisées pour le même bloc d'objet (suspendre l'exécution) jusqu'à ce que le premier fil est fait avec l'objet.

En second lieu, lorsqu'une sorties de méthode synchronisée, il établit automatiquement une relation qui se passe, avant toute invocation ultérieure d'une méthode synchronisée pour le même objet. Cela garantit que les changements à l'état de l'objet sont visibles à toutes les discussions.

Notez que les constructeurs ne peuvent pas être synchronisés - en utilisant le mot-clé synchronisé avec un constructeur est une erreur de syntaxe. Constructeurs ne fait Synchroniser les pas de sens, car seul le fil qui crée un objet doit avoir accès alors qu'il est en cours de construction.

Déclaration Synchronisé

Contrairement aux méthodes synchronisées, les déclarations synchronisées doivent préciser l'objet qui fournit le verrou intrinsèque: Le plus souvent je l'utiliser pour synchroniser l'accès à une liste ou la carte mais je ne veux pas bloquer l'accès à toutes les méthodes de l'objet.

Q: verrous internes et de synchronisation La synchronisation est construit autour d'une entité interne connue sous le verrou interne ou verrouillage du moniteur. (La spécification API fait souvent référence à cette entité comme un simple « moniteur ».) Verrous internes jouent un rôle dans les deux aspects de la synchronisation: l'application d'un accès exclusif à l'état d'un objet et l'établissement passe-avant les relations qui sont essentielles à la visibilité.

Chaque objet a un verrou intrinsèque qui lui est associée. Par convention, un fil qui a besoin d'un accès exclusif et cohérente aux champs d'un objet doit acquérir un verrou intrinsèque de l'objet avant d'y accéder, puis relâchez le verrou intrinsèque quand il est fait avec eux. Un fil est dit posséder le verrou intrinsèque entre le moment où il a acquis le verrou et libéré le verrou. Tant qu'un fil possède un verrou intrinsèque, aucun autre thread ne peut acquérir le même verrou. L'autre thread bloque lorsqu'il tente d'acquérir le verrou.

package test;

public class SynchTest implements Runnable {  
    private int c = 0;

    public static void main(String[] args) {
        new SynchTest().test();
    }

    public void test() {
        // Create the object with the run() method
        Runnable runnable = new SynchTest();
        Runnable runnable2 = new SynchTest();
        // Create the thread supplying it with the runnable object
        Thread thread = new Thread(runnable,"thread-1");
        Thread thread2 = new Thread(runnable,"thread-2");
//      Here the key point is passing same object, if you pass runnable2 for thread2,
//      then its not applicable for synchronization test and that wont give expected
//      output Synchronization method means "it is not possible for two invocations
//      of synchronized methods on the same object to interleave"

        // Start the thread
        thread.start();
        thread2.start();
    }

    public synchronized  void increment() {
        System.out.println("Begin thread " + Thread.currentThread().getName());
        System.out.println(this.hashCode() + "Value of C = " + c);
//      If we uncomment this for synchronized block, then the result would be different
//      synchronized(this) {
            for (int i = 0; i < 9999999; i++) {
                c += i;
            }
//      }
        System.out.println("End thread " + Thread.currentThread().getName());
    }

//    public synchronized void decrement() {
//        System.out.println("Decrement " + Thread.currentThread().getName());
//    }

    public int value() {
        return c;
    }

    @Override
    public void run() {
        this.increment();
    }
}

Vérification croisée avec différentes sorties méthode synchronisée, bloc et sans synchronisation.

Note:. statique les méthodes et les blocs synchronisés fonctionnent sur l'objet de classe

public class MyClass {
   // locks MyClass.class
   public static synchronized void foo() {
// do something
   }

   // similar
   public static void foo() {
      synchronized(MyClass.class) {
// do something
      }
   }
}

Lorsque compilateur java convertit votre code source en code octet, il gère très différemment les méthodes synchronisées et des blocs synchronisés.

Lorsque la JVM exécute une méthode synchronisée, le fil d'exécution détermine que la structure de method_info du procédé présente l'indicateur ACC_SYNCHRONIZED, il acquiert automatiquement le verrouillage de l'objet, appelle la méthode, et libère le verrouillage. Si une exception se produit, le thread libère automatiquement le verrouillage.

Synchroniser un bloc de méthode, d'autre part, contourne le intégré dans JVM support pour l'acquisition de verrouillage d'un objet et la gestion des exceptions et exige que la fonctionnalité soit écrit explicitement dans le code d'octets. Si vous lisez le code d'octets pour une méthode avec un bloc synchronisé, vous verrez plus d'une douzaine d'autres opérations pour gérer cette fonctionnalité.

Cela montre appels à générer à la fois une méthode synchronisée et un bloc synchronisé:

public class SynchronizationExample {
    private int i;

    public synchronized int synchronizedMethodGet() {
        return i;
    }

    public int synchronizedBlockGet() {
        synchronized( this ) {
            return i;
        }
    }
}

La méthode de synchronizedMethodGet() génère le code d'octet suivante:

0:  aload_0
1:  getfield
2:  nop
3:  iconst_m1
4:  ireturn

Et voici le code octet de la méthode synchronizedBlockGet():

0:  aload_0
1:  dup
2:  astore_1
3:  monitorenter
4:  aload_0
5:  getfield
6:  nop
7:  iconst_m1
8:  aload_1
9:  monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow

Une différence significative entre le procédé et le bloc synchronisé est que, généralement bloc synchronisé à réduire la portée de verrouillage. Comme la portée de verrouillage est inversement proportionnelle à la performance, est toujours préférable de verrouiller uniquement la section de code critique. L'un des meilleurs exemples de l'utilisation de bloc synchronisé est double vérification de verrouillage dans le motif Singleton où au lieu de toute méthode de verrouillage getInstance() nous fermons uniquement la section de code critique qui est utilisé pour créer une instance Singleton. Cela améliore considérablement les performances car le verrouillage est uniquement nécessaire une ou deux fois.

Lors de l'utilisation des méthodes synchronisées, vous devez prendre des précautions supplémentaires si vous mélangez les deux méthodes synchronisées statiques synchronisées et non statiques.

Le plus souvent je l'utiliser pour synchroniser l'accès à une liste ou la carte mais je ne veux pas bloquer l'accès à toutes les méthodes de l'objet.

Dans le code suivant un fil modifiant la liste ne bloque pas l'attente d'un fil qui est en train de modifier la carte. Si les méthodes ont été synchronisées sur l'objet puis chaque méthode devrait attendre même si les modifications qu'ils font seraient pas en conflit.

private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();

public void put( String s, Bar b ) {
  synchronized( myMap ) {
    myMap.put( s,b );
    // then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public void hasKey( String s, ) {
  synchronized( myMap ) {
    myMap.hasKey( s );
  }
}

public void add( Foo f ) {
  synchronized( myList ) {
    myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public Thing getMedianFoo() {
  Foo med = null;
  synchronized( myList ) {
    Collections.sort(myList);
    med = myList.get(myList.size()/2); 
  }
  return med;
}

Avec des blocs synchronisés, vous pouvez avoir plusieurs synchroniseurs, de sorte que plusieurs choses en même temps, mais non contradictoires peuvent aller en même temps.

méthodes peuvent être vérifiées synchronisées en utilisant l'API de réflexion. Cela peut être utile pour tester certains contrats, tels que toutes les méthodes dans le modèle sont synchronisés .

Les impressions dans le code suivant toutes les méthodes synchronisées de Hashtable:

for (Method m : Hashtable.class.getMethods()) {
        if (Modifier.isSynchronized(m.getModifiers())) {
            System.out.println(m);
        }
}

Remarque importante sur l'utilisation du bloc synchronisé: attention à ce que vous utilisez comme objet verrou

L'extrait de code de user2277816 ci-dessus illustre ce point en ce qu 'une référence à une chaîne de caractères est utilisée comme objet de verrouillage. Sachez que littéraux de chaîne sont automatiquement internées en Java et vous devriez commencer à voir le problème: chaque morceau de code qui synchronise sur le « verrouillage » littérale, partage le même verrou! Cela peut facilement conduire à des blocages avec des morceaux complètement indépendants de code.

Il est pas seulement des objets String que vous devez être prudent avec. primitives Boxed sont aussi un danger, car autoboxing et les méthodes de ValueOf peuvent réutiliser les mêmes objets, en fonction de la valeur.

Pour plus d'informations, voir: https: / /www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused

Souvent, l'aide d'un verrou sur un niveau de la méthode est trop grossière. Pourquoi enfermer un morceau de code qui n'a pas accès à des ressources partagées en verrouillant une méthode entière. Étant donné que chaque objet a une serrure, vous pouvez créer des objets factices pour mettre en œuvre la synchronisation de niveau bloc. Le niveau du bloc est plus efficace car il ne se verrouille pas toute la méthode.

Voici quelques exemples

Méthode Niveau

class MethodLevel {

  //shared among threads
SharedResource x, y ;

public void synchronized method1() {
   //multiple threads can't access
}
public void synchronized method2() {
  //multiple threads can't access
}

 public void method3() {
  //not synchronized
  //multiple threads can access
 }
}

Bloquer niveau

class BlockLevel {
  //shared among threads
  SharedResource x, y ;

  //dummy objects for locking
  Object xLock = new Object();
  Object yLock = new Object();

    public void method1() {
     synchronized(xLock){
    //access x here. thread safe
    }

    //do something here but don't use SharedResource x, y
    // because will not be thread-safe
     synchronized(xLock) {
       synchronized(yLock) {
      //access x,y here. thread safe
      }
     }

     //do something here but don't use SharedResource x, y
     //because will not be thread-safe
    }//end of method1
 }

[Modifier]

Pour Collection comme Vector et Hashtable ils sont synchronisés lorsque ArrayList ou HashMap ne sont pas et vous devez définir mot-clé synchronisé ou collections méthode synchronisée invoquent:

Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list

La seule différence: blocs synchronisés permet verrouillage granulaire contrairement méthode synchronisée

bloc Fondamentalement synchronized ou méthodes ont été utilisées pour écrire le code fil en toute sécurité en évitant les erreurs d'incohérence de la mémoire.

Cette question est très ancienne et beaucoup de choses ont changé au cours des 7 dernières années. constructions de programmation nouveaux ont été mis en place pour la sécurité des threads.

Vous pouvez obtenir la sécurité de fil en utilisant l'API avancée au lieu de concurrency blocs synchronied. Cette documentation fournit construit une bonne programmation pour assurer la sécurité de fil.

Objets verrouillage soutien idiomes de verrouillage qui simplifient de nombreuses applications concurrentes.

Executors définir une API de haut niveau pour le lancement et la gestion de threads. implémentations fournies par Executor java.util.concurrent assurent la gestion du pool de threads adapté pour des applications à grande échelle.

Collections simultanées le rendre plus facile à gérer de grandes collections de données, et peut réduire considérablement le besoin de synchronisation.

Variables atomiques ont des caractéristiques qui réduisent au minimum la synchronisation et éviter les erreurs de cohérence de la mémoire.

ThreadLocalRandom (dans JDK 7) permet la génération efficace de nombres pseudo-aléatoires à partir de plusieurs threads.

Mieux remplacer synchronisée est ReentrantLock , qui utilise l'API Lock

  

A rentrante exclusion mutuelle de verrouillage avec le même comportement de base et sémantique que le verrouillage du moniteur implicite accessible en utilisant des méthodes et des déclarations synchronisées, mais avec des fonctionnalités étendues.

Exemple de verrous:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

Reportez-vous à java.util .concurrent et paquets java.util.concurrent.atomic aussi pour d'autres constructions de programmation.

Reportez-vous à cette question liée aussi:

synchronisation vs verrouillage

Procédé synchronisé est utilisé pour le verrouillage de tous les objets bloc synchronisé est utilisé pour verrouiller l'objet spécifique

En général ce sont essentiellement les mêmes autre que d'être explicite sur l'écran de l'objet qui est utilisé contre l'implicite de cet objet. Un inconvénient des méthodes synchronisées que je pense est parfois négligé est que l'utilisation de la « cette » référence à synchroniser sur vous laissez ouverts la possibilité d'objets extérieurs de verrouillage sur le même objet. Cela peut être un bug très subtil si vous exécutez en elle. Synchronisation sur un objet explicite interne ou tout autre domaine existant peut éviter ce problème, l'encapsulation complètement la synchronisation.

Comme nous l'avons dit ici bloc synchronisé peut utiliser la variable définie par l'utilisateur comme objet de verrouillage, lorsque la fonction synchronisée utilise uniquement « ce ». Et bien sûr, vous pouvez manipuler avec des zones de votre fonction qui devrait être synchronisés. Mais tout le monde dit que pas de différence entre la fonction synchronisée et bloc qui couvre toute la fonction en utilisant « cet » objet comme verrou. Ce n'est pas vrai, la différence est dans le code d'octets qui sera généré dans les deux situations. En cas d'utilisation du bloc synchronisé doit être allouée variable locale qui tient référence à « ce ». Et comme conséquence, nous aurons un peu plus grande taille pour la fonction (pas pertinente si vous avez seulement quelques nombre de fonctions).

Une explication plus détaillée de la différence que vous pouvez trouver ici: http://www.artima.com/insidejvm/ed2/threadsynchP.html

Dans le cas des méthodes synchronisées, verrouillage sera acquis sur un objet. Mais si vous allez avec le bloc synchronisé vous avez une option pour spécifier un objet sur lequel le verrou est acquis.

Exemple:

    Class Example {
    String test = "abc";
    // lock will be acquired on String  test object.
    synchronized (test) {
        // do something
    }

   lock will be acquired on Example Object
   public synchronized void testMethod() {
     // do some thing
   } 

   }

Je sais que c'est une vieille question, mais avec ma lecture rapide des réponses ici, je ne vois pas vraiment quelqu'un mentionner que parfois une méthode synchronized peut être la mauvaise verrouillage.
De Programmation concurrente en Java (p 72.):

public class ListHelper<E> {
  public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...

public syncrhonized boolean putIfAbsent(E x) {
 boolean absent = !list.contains(x);
if(absent) {
 list.add(x);
}
return absent;
}

Le code ci-dessus a le Apparence d'être thread-safe. Cependant, en réalité, ce n'est pas. Dans ce cas, le verrou est obtenu sur l'instance de la classe. Cependant, il est possible que l'être modifié par un autre thread liste ne pas utiliser cette méthode. L'approche correcte serait d'utiliser

public boolean putIfAbsent(E x) {
 synchronized(list) {
  boolean absent = !list.contains(x);
  if(absent) {
    list.add(x);
  }
  return absent;
}
}

Le code ci-dessus pourrait bloquer Tous les sujets essayant de modifier liste de modifier la liste jusqu'à ce que le bloc synchronisé est terminée.

En pratique, l'avantage de méthodes synchronisées sur des blocs synchronisés est qu'ils sont plus résistants à con; parce que vous ne pouvez pas choisir un objet arbitraire pour verrouiller, vous ne pouvez pas abuser de la syntaxe de méthode synchronisée pour faire des choses stupides comme le verrouillage sur une chaîne littérale ou de verrouillage sur le contenu d'un champ mutable qui obtient changé de sous les fils.

D'autre part, avec des méthodes synchronisées vous ne pouvez pas protéger le verrou de se faire acquis par un fil qui peut obtenir une référence à l'objet.

Donc, en utilisant synchronisé comme modificateur sur les méthodes est mieux à protéger vos vaches-es travailleurs de se blesser, tout en utilisant des blocs synchronisés conjointement avec des objets de verrouillage finale privée est mieux à protéger votre propre code de la vache-es travailleurs.

Dans un résumé de spécification Java: http://www.cs.cornell.edu/andru/javaspec/17 .doc.html

  

L'état synchronisé (§14.17) calcule une référence à un objet;   il tente ensuite d'effectuer une action de verrouillage sur cet objet et ne   aller plus loin jusqu'à ce que l'action de blocage a terminé avec succès. ...

     

Une méthode synchronisée (§8.4.3.5) effectue automatiquement une action de verrouillage   quand elle est invoquée; son corps n'a pas été exécuté jusqu'à ce que l'action de verrouillage a   complété avec succès. Si la méthode est une méthode d'instance , il   verrouille la serrure associée à l'instance pour laquelle il a été invoqué   (Autrement dit, l'objet qui sera appelé pendant l'exécution de cette   le corps de la méthode). Si la méthode est statique , il verrouille la   serrure associée à l'objet de classe qui représente la classe   où la méthode est définie. ...

Sur la base de ces descriptions, je dirais que les réponses les plus précédentes sont correctes, et une méthode synchronisée pourrait être particulièrement utile pour les méthodes statiques, où vous auriez autrement pour savoir comment obtenir le « objet de classe qui représente la classe dans laquelle la méthode a été définie. "

Edit: Je pensais à l'origine ce sont des citations de la spécification Java réelle. Précisé que cette page est juste un résumé / explication de la spécification

TLDR; Ni utiliser le modificateur de synchronized, ni l'expression de synchronized(this){...} mais synchronized(myLock){...}myLock est un champ de dernière instance tenant un objet privé

.

La différence entre l'utilisation du modificateur de synchronized sur la déclaration de la méthode et l'expression de synchronized(..){ } dans le corps de la méthode sont celle-ci:

  • Le modificateur de synchronized spécifié sur la signature de la méthode
    1. est visible dans la JavaDoc généré,
    2. est déterminable par programme réflexion lors du test de modification d'une méthode pour Modifier.SYNCHRONIZED ,
    3. nécessite moins de frappe et indention par rapport à synchronized(this) { .... } et
    4. (en fonction de votre IDE) est visible dans l'achèvement du plan de la classe et le code,
    5. utilise l'objet this comme verrou lorsqu'ils sont déclarés sur la méthode non statique ou la classe externe lorsque déclarée sur une méthode statique.
  • L'expression synchronized(...){...} vous permet
    1. pour que la synchronisation de l'exécution de certaines parties du corps d'un procédé,
    2. pour être utilisé dans un constructeur ou un ( statique ) bloc d'initialisation,
    3. pour choisir l'objet de verrouillage qui contrôle l'accès synchronisé.

Cependant, en utilisant le modificateur de synchronized ou synchronized(...) {...} avec this comme l'objet de verrouillage (comme dans synchronized(this) {...}), ont le même inconvénient. Les deux utilisent comme objet de verrouillage propre instance de pour synchroniser sur. Ceci est dangereux parce que non seulement l'objet lui-même, mais tout tout autre objet extérieur / code qui contient une référence à cet objet peut également l'utiliser comme un verrou de synchronisation avec des effets secondaires potentiellement graves (dégradation des performances et des interblocages).

Par conséquent meilleure pratique consiste à n'utiliser le modificateur de synchronized, ni l'expression synchronized(...) conjointement avec this comme objet de verrouillage, mais un objet de verrouillage privé à cet objet. Par exemple:

public class MyService {
    private final lock = new Object();

    public void doThis() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }

    public void doThat() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }
}

Vous pouvez également utiliser des objets de verrouillage multiples, mais une attention particulière doit être prise pour assurer que cela ne donne pas lieu à des blocages quand il est utilisé imbriqué.

public class MyService {
    private final lock1 = new Object();
    private final lock2 = new Object();

    public void doThis() {
       synchronized(lock1) {
          synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThat() and doMore().
          }
    }

    public void doThat() {
       synchronized(lock1) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doMore() may execute concurrently
        }
    }

    public void doMore() {
       synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doThat() may execute concurrently
        }
    }
}

Je suppose que cette question est la différence entre thread-safe Singleton et initialisation Lazy avec verrouillage Revérifiez . Je me réfère toujours à cet article quand je dois mettre en œuvre certaines singleton spécifiques.

Eh bien, c'est un thread-safe Singleton :

// Java program to create Thread Safe 
// Singleton class 
public class GFG  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static GFG instance; 

  private GFG()  
  { 
    // private constructor 
  } 

 //synchronized method to control simultaneous access 
  synchronized public static GFG getInstance()  
  { 
    if (instance == null)  
    { 
      // if instance is null, initialize 
      instance = new GFG(); 
    } 
    return instance; 
  } 
} 
  

Avantages:

     
      
  1. initialisation Lazy est possible.

  2.   
  3. Il est thread-safe.

  4.   
     

Moins:

     
      
  1. méthode getInstance () est synchronisée de sorte qu'il provoque un ralentissement des performances que plusieurs threads ne peut pas accéder simultanément.
  2.   

Ceci est un initialisation Lazy avec verrouillage Revérifiez :

// Java code to explain double check locking 
public class GFG  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static GFG instance; 

  private GFG()  
  { 
    // private constructor 
  } 

  public static GFG getInstance() 
  { 
    if (instance == null)  
    { 
      //synchronized block to remove overhead 
      synchronized (GFG.class) 
      { 
        if(instance==null) 
        { 
          // if instance is null, initialize 
          instance = new GFG(); 
        } 

      } 
    } 
    return instance; 
  } 
} 
  

Avantages:

     
      
  1. initialisation Lazy est possible.

  2.   
  3. Il est également enfilez sûr.

  4.   
  5. Performance réduite en raison du mot-clé synchronisé est surmonté.

  6.   
     

Moins:

     
      
  1. La première fois, il peut affecter les performances.

  2.   
  3. contre. du procédé de verrouillage de double vérification est supportable de sorte qu'il peut être   utilisé pour des applications de haute performance multi-threads.

  4.   

S'il vous plaît se référer à cet article pour plus de détails:

https://www.geeksforgeeks.org/java- singleton-design-pattern-pratiques-examples /

Synchronisation avec des fils. 1) Ne jamais utiliser synchronisées (cela) dans un fil, il ne fonctionne pas. Synchronisation avec (ce) utilise le fil courant en tant que l'objet de fil de verrouillage. Etant donné que chaque fil est indépendant des autres fils, il n'y a pas de coordination de la synchronisation. 2) Tests de code montrent que Java 1.6 sur Mac la synchronisation de méthode ne fonctionne pas. 3) synchronisé (lockObj) où lockObj est un objet partagé commun de tous les fils de synchronisation sur elle fonctionnera. 4) ReenterantLock.lock () et le travail de .unlock (). Voir tutoriels Java pour cela.

Le code suivant montre ces points. Il contient également le vecteur thread-safe qui serait remplacé par le ArrayList, pour montrer que beaucoup de threads en ajoutant un vecteur ne perdent aucune information, alors que la même chose avec un ArrayList peut perdre des informations. 0) Code actuel montre la perte d'informations en raison des conditions de course A) Commentaire du courant marqué Une ligne et décommentez la ligne A au-dessus, puis exécutez, la méthode perd des données, mais il ne devrait pas. B) l'étape inverse A, B et uncomment // bloc d'extrémité}. Exécutez ensuite pour voir les résultats sans perte de données C) Commentaire sur B, C. uncomment Run, voir la synchronisation sur (ce) perd des données, comme prévu. Ne pas avoir le temps de remplir toutes les variations, espérons que cette aide. Si la synchronisation sur (ce), ou les travaux de synchronisation de la méthode, s'il vous plaît indiquer quelle version de Java et OS vous avez testé. Merci.

import java.util.*;

/** RaceCondition - Shows that when multiple threads compete for resources 
     thread one may grab the resource expecting to update a particular 
     area but is removed from the CPU before finishing.  Thread one still 
     points to that resource.  Then thread two grabs that resource and 
     completes the update.  Then thread one gets to complete the update, 
     which over writes thread two's work.
     DEMO:  1) Run as is - see missing counts from race condition, Run severa times, values change  
            2) Uncomment "synchronized(countLock){ }" - see counts work
            Synchronized creates a lock on that block of code, no other threads can 
            execute code within a block that another thread has a lock.
        3) Comment ArrayList, unComment Vector - See no loss in collection
            Vectors work like ArrayList, but Vectors are "Thread Safe"
         May use this code as long as attribution to the author remains intact.
     /mf
*/ 

public class RaceCondition {
    private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
//  private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)

    private String countLock="lock";    // Object use for locking the raceCount
    private int raceCount = 0;        // simple add 1 to this counter
    private int MAX = 10000;        // Do this 10,000 times
    private int NUM_THREADS = 100;    // Create 100 threads

    public static void main(String [] args) {
    new RaceCondition();
    }

    public RaceCondition() {
    ArrayList<Thread> arT = new ArrayList<Thread>();

    // Create thread objects, add them to an array list
    for( int i=0; i<NUM_THREADS; i++){
        Thread rt = new RaceThread( ); // i );
        arT.add( rt );
    }

    // Start all object at once.
    for( Thread rt : arT ){
        rt.start();
    }

    // Wait for all threads to finish before we can print totals created by threads
    for( int i=0; i<NUM_THREADS; i++){
        try { arT.get(i).join(); }
        catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
    }

    // All threads finished, print the summary information.
    // (Try to print this informaiton without the join loop above)
    System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
                MAX*NUM_THREADS, raceList.size(), raceCount );
    System.out.printf("Array lost %,d. Count lost %,d\n",
             MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
    }   // end RaceCondition constructor



    class RaceThread extends Thread {
    public void run() {
        for ( int i=0; i<MAX; i++){
        try {
            update( i );        
        }    // These  catches show when one thread steps on another's values
        catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
        catch( OutOfMemoryError oome ) { System.out.print("O"); }
        }
    }

    // so we don't lose counts, need to synchronize on some object, not primitive
    // Created "countLock" to show how this can work.
    // Comment out the synchronized and ending {, see that we lose counts.

//    public synchronized void update(int i){   // use A
    public void update(int i){                  // remove this when adding A
//      synchronized(countLock){            // or B
//      synchronized(this){             // or C
        raceCount = raceCount + 1;
        raceList.add( i );      // use Vector  
//          }           // end block for B or C
    }   // end update

    }   // end RaceThread inner class


} // end RaceCondition outter class
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top