Domanda

Uno può dirmi il vantaggio di metodo sincronizzato su blocco sincronizzato con un esempio?

È stato utile?

Soluzione

  

Qualcuno può dirmi il vantaggio del metodo sincronizzato sul blocco sincronizzato con un esempio? Grazie.

Non esiste un chiaro vantaggio di utilizzare metodo sincronizzato sul blocco.

Forse l'unico (ma non lo definirei un vantaggio) è che non è necessario includere il this oggetto di riferimento.

Metodo:

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

Blocco:

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

Vedi? Alcun vantaggio a tutti.

Blocchi do hanno vantaggi rispetto ai metodi, però, per lo più in termini di flessibilità, perché è possibile utilizzare un altro oggetto come blocco, mentre la sincronizzazione il metodo sarebbe bloccare l'intero oggetto.

Confronto:

// 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) { 
        ... 
    }
}

Anche se il metodo cresce è ancora possibile mantenere la sezione sincronizzato separato:

 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
}

Altri suggerimenti

L'unica differenza è che un blocco sincronizzato può scegliere quale oggetto si sincronizza su. Un metodo sincronizzato può utilizzare solo 'this' (o l'istanza di classe corrispondente per un metodo di classe sincronizzato). Ad esempio, questi sono semanticamente equivalenti:

synchronized void foo() {
  ...
}

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

Il secondo è più flessibile poiché può competere per il blocco associato di qualsiasi oggetto, una variabile membro spesso. E 'anche più granulare, perché si potrebbe avere il codice concomitante esecuzione prima e dopo il blocco, ma ancora all'interno del metodo. Naturalmente, si può facilmente utilizzare un metodo sincronizzato dal refactoring del codice concorrente in metodi non sincronizzati separati. Utilizzare qualsiasi rende il codice più comprensibile.

sincronizzato Metodo

Pro:

  • Il vostro IDE può indicare i metodi sincronizzati.
  • La sintassi è più compatta.
  • le forze per dividere i blocchi sincronizzati metodi separati.

Contro:

  • Sincronizza a questo e quindi rende possibile outsider per la sincronizzazione ad esso troppo.
  • È difficile spostare codice esterno al blocco sincronizzato.

blocco sincronizzato

Pro:

  • Permette di utilizzare una variabile privata per la serratura e quindi forzando la serratura di rimanere all'interno della classe.
  • blocchi sincronizzate possono essere trovati cercando riferimenti alla variabile.

Contro:

  • La sintassi è più complicato e quindi rende il codice più difficile da leggere.

Personalmente preferisco utilizzando metodi sincronizzati con le classi focalizzati solo per la cosa che necessitano di sincronizzazione. Tale classe dovrebbe essere il più piccolo possibile e quindi dovrebbe essere facile da rivedere la sincronizzazione. Altri non hanno bisogno di preoccuparsi di sincronizzazione.

La differenza principale è che se si utilizza un blocco sincronizzato si può bloccare su un oggetto diverso da questo che permette di essere molto più flessibile.

Si supponga di avere una coda di messaggi e produttori di messaggi multipli e consumatori. Non vogliamo i produttori a interferire con l'altro, ma i consumatori dovrebbero essere in grado di recuperare i messaggi senza dover attendere per i produttori. Così abbiamo appena creiamo un oggetto

Object writeLock = new Object();

E da ora in poi ogni volta che un produttore vuole aggiungere un nuovo messaggio che abbiamo appena Lock On che:

synchronized(writeLock){
  // do something
}

Quindi, i consumatori possono ancora leggere, e produttori saranno bloccati.

metodo sincronizzato

metodi sincronizzati hanno due effetti.
In primo luogo, quando un thread sta eseguendo un metodo sincronizzato per un oggetto, tutti gli altri thread che richiamano sincronizzati metodi per lo stesso blocco oggetto (sospendere l'esecuzione) fino al primo filo avviene con l'oggetto.

In secondo luogo, quando un sincronizzate esce metodo, si stabilisce automaticamente accade-prima relazione con ogni successiva invocazione di un metodo sincronizzato per lo stesso oggetto. Ciò garantisce che modifica lo stato dell'oggetto sono visibili tutti i filetti.

Si noti che i costruttori non possono essere sincronizzate - utilizzando la parola chiave sincronizzato con un costruttore è un errore di sintassi. Sincronizzazione costruttori non ha senso, perché solo il filo che crea un oggetto deve avere accesso ad esso, mentre è in fase di costruzione.

Dichiarazione sincronizzato

A differenza dei metodi sincronizzati, dichiarazioni sincronizzare deve specificare l'oggetto che fornisce il blocco intrinseco: Molto spesso Io lo uso per sincronizzare l'accesso a un elenco o mappa, ma io non voglio di bloccare l'accesso a tutti i metodi dell'oggetto.

Q: intrinseci Serrature e sincronizzazione La sincronizzazione è costruito attorno ad un'entità interna nota come la serratura intrinseca o blocco del monitor. (La specifica API spesso si riferisce a questa entità semplicemente come "monitor.") Serrature intrinseche giocano un ruolo in entrambi gli aspetti della sincronizzazione: applicare accesso esclusivo a stato e stabilire accade-prima relazioni che sono essenziali per la visibilità di un oggetto.

Ogni oggetto ha un blocco intrinseca ad esso associati. Per convenzione, un filo che deve accedere esclusivo e coerente ai campi di un oggetto deve acquisire serratura intrinseca dell'oggetto prima di accedere, e quindi rilasciare il blocco intrinseca quando è fatto con loro. Un filo si dice che possiede blocco intrinseco tra il tempo che ha acquisito la serratura e rilasciato il blocco. Finché un filo possiede una serratura intrinseco, nessun altro thread può acquisire la stessa serratura. L'altro filo si blocca quando tenta di acquisire il blocco.

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();
    }
}

controlla trasversale diverse uscite con sincronizzato metodo, blocco e senza sincronizzazione.

Nota:. static i metodi e blocchi sincronizzati lavorare sul oggetto Class

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

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

Quando java compilatore converte il codice sorgente in bytecode, gestisce i metodi sincronizzati e blocchi sincronizzati in modo molto diverso.

Quando la JVM esegue un metodo sincronizzato, il filo di esecuzione identifica che la struttura method_info del metodo ha il flag ACC_SYNCHRONIZED, quindi acquisisce automaticamente blocco dell'oggetto, chiama il metodo, e rilascia il blocco. Se si verifica un'eccezione, il filo rilascia automaticamente il blocco.

Sincronizzazione di un blocco del metodo, invece, bypassa il JVM supporto integrato per l'acquisizione e la serratura eccezione manipolazione di un oggetto e richiede che la funzionalità essere scritto esplicitamente nel codice byte. Se andate a leggere il codice di byte per un metodo con un blocco sincronizzato, si vedrà più di una dozzina di operazioni aggiuntive per gestire questa funzionalità.

Questo dimostra chiamate per generare sia un metodo sincronizzato e un blocco sincronizzato:

public class SynchronizationExample {
    private int i;

    public synchronized int synchronizedMethodGet() {
        return i;
    }

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

Il metodo synchronizedMethodGet() genera il seguente codice di byte:

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

Ed ecco il codice di byte dal metodo 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

Una differenza significativa tra metodo sincronizzato e blocco è che, blocco sincronizzato generalmente ridurre la portata della serratura. Come applicazione di blocco è inversamente proporzionale alle prestazioni, la sua sempre meglio bloccare solo sezione critica del codice. Uno dei migliori esempio di utilizzo di blocco sincronizzato è ricontrollato bloccaggio in pattern Singleton dove invece di bloccare tutto il metodo getInstance() abbiamo solo bloccare sezione critica di codice che viene utilizzato per creare l'istanza Singleton. Ciò migliora la prestazione notevolmente a causa di bloccaggio è necessaria solo una o due volte.

Durante l'utilizzo di metodi sincronizzati, è necessario fare particolare attenzione se si mescolano entrambi i metodi sincronizzati sincronizzati e non statici statici.

Il più delle volte io uso questo per sincronizzare l'accesso a un elenco o una mappa, ma io non voglio di bloccare l'accesso a tutti i metodi dell'oggetto.

Nel seguente codice di un filo modificare l'elenco non bloccherà in attesa di un thread che sta modificando la mappa. Se i metodi sono stati sincronizzati sull'oggetto quindi ogni metodo avrebbe dovuto aspettare, anche se le modifiche che stanno facendo non sarebbe in conflitto.

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;
}

Con blocchi sincronizzati, è possibile avere più sincronizzatori, in modo che più simultaneo, ma non in conflitto le cose possono andare avanti allo stesso tempo.

metodi sincroni possono essere controllati mediante riflessione API. Questo può essere utile per testare alcuni contratti, come tutti i metodi nel modello sono sincronizzati .

Il seguente codice stampa frammento tutti i metodi sincronizzati di Hashtable:

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

Nota per l'utilizzo del blocco sincronizzato: attenti a ciò che si utilizza oggetto come blocco

Il frammento di codice da user2277816 sopra illustra questo punto che un riferimento a una stringa letterale viene utilizzato come chiusura oggetto. Rendetevi conto che stringa letterali sono internati automaticamente in Java e si dovrebbe cominciare a vedere il problema: ogni pezzo di codice che consente di sincronizzare il "blocco" letterale, condivide lo stesso blocco! Questo può facilmente condurre a situazioni di stallo con pezzi completamente indipendenti di codice.

Non è solo oggetti String che è necessario stare attenti con. primitive in scatola sono anche un pericolo, dal momento che autoboxing ei metodi valueOf possono riutilizzare gli stessi oggetti, a seconda del valore.

Per ulteriori informazioni si veda: https: / /www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused

Spesso utilizzando un blocco su un livello di metodo è troppo rude. Perché bloccare un pezzo di codice che non accedere alle risorse condivise da rinchiudere un intero metodo. Poiché ogni oggetto ha una serratura, è possibile creare oggetti fittizi per implementare la sincronizzazione a livello di blocco. Il livello di blocco è più efficiente perché non blocca l'intero metodo.

Ecco alcuni esempi

Metodo Livello

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
 }
}

a livello di blocco

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
 }

[Edit]

Per Collection come Vector e Hashtable sono sincronizzati quando ArrayList o HashMap non sono ed è necessario impostare parola chiave sincronizzato o invocano Collezioni metodo sincronizzato:

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

L'unica differenza: blocchi sincronizzati permette bloccaggio granulare differenza metodo sincronizzato

blocco o metodi Fondamentalmente synchronized sono stati utilizzati per scrivere filo codice sicuro evitando errori incoerenza memoria.

Questa domanda è molto vecchio e molte cose sono state modificate nel corso degli ultimi 7 anni. Nuovi costrutti di programmazione sono stati introdotti per la sicurezza thread.

È possibile ottenere sicurezza thread utilizzando advanced API concorrenza invece di blocchi synchronied. Questa documentazione pagina fornisce una buona programmazione costruisce per raggiungere la sicurezza thread.

bloccare gli oggetti sostegno idiomi che semplificano molte applicazioni simultanee bloccaggio.

Esecutori definire un'API di alto livello per lanciare e gestire thread. implementazioni esecutore fornite da java.util.concurrent forniscono gestione piscina filo adatto per applicazioni su larga scala.

simultanee Collezioni rendere più facile da gestire grandi collezioni di dati, e può ridurre notevolmente la necessità per la sincronizzazione.

Variabili Atomic hanno caratteristiche che minimizzano la sincronizzazione e contribuire ad evitare errori di coerenza memoria.

ThreadLocalRandom (in JDK 7) prevede efficiente generazione di numeri pseudocasuali da più thread.

Una migliore sostituto per sincronizzato è ReentrantLock , che utilizza API Lock

  

Una Serratura mutua esclusione rientrante con lo stesso comportamento di base e la semantica come il blocco del monitor implicito accede utilizzando metodi e dichiarazioni sincronizzati, ma con funzionalità estese.

Esempio con serrature:

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

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

Fare riferimento a java.util .concurrent e java.util.concurrent.atomic pacchetti troppo per altri costrutti di programmazione.

Fare riferimento a questa domanda relativa troppo:

Sincronizzazione vs blocco

metodo sincronizzato è usato per il blocco di tutti gli oggetti blocco sincronizzato viene utilizzato per bloccare l'oggetto specifico

In generale questi sono per lo più lo stesso oltre ad essere esplicito sul monitor dell'oggetto che viene utilizzato contro l'implicita questo oggetto. Uno svantaggio dei metodi sincronizzati che ritengo volte trascurato è che utilizzando il "questo" riferimento alla sincronizzarsi su si sta lasciando aperta la possibilità di oggetti esterni bloccaggio sullo stesso oggetto. Che può essere un bug molto sottile se si esegue in esso. Sincronizzazione a un oggetto esplicito interno o altro campo esistente può evitare questo problema, incapsulando completamente la sincronizzazione.

Come già detto blocco qui sincronizzato può utilizzare variabile definito dall'utente come oggetto di blocco, quando la funzione sincronizzata utilizza solo "questo". E, naturalmente, è possibile manipolare con aree di vostra funzione che devono essere sincronizzati. Ma tutti dicono che c'è differenza tra la funzione sincronizzato e blocco che si estende su tutta la funzione che utilizza "questo" oggetto come blocco. Questo non è vero, la differenza è nel codice byte che viene generato in entrambe le situazioni. In caso di utilizzo di blocco sincronizzato dovrebbero essere assegnati variabile locale che detiene riferimento a "questo". E come risultato avremo dimensioni un po 'più grande per la funzione (non rilevante se hai solo poche serie di funzioni).

spiegazione più dettagliata delle differenze si possono trovare qui: http://www.artima.com/insidejvm/ed2/threadsynchP.html

Nei metodi sincronizzati, serratura saranno acquisite su un oggetto. Ma se si va con blocco sincronizzato si ha la possibilità di specificare un oggetto su cui verrà acquisito il blocco.

Esempio:

    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
   } 

   }

So che questa è una vecchia questione, ma con la mia lettura veloce delle risposte qui, non ho davvero visto nessuno menziona che a volte un metodo synchronized può essere il sbagliato di blocco.
Da Java Concurrency in Practice (pag 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;
}

Il codice sopra ha il aspetto di essere thread-safe. Tuttavia, in realtà non lo è. In questo caso il blocco è ottenuto sulla istanza della classe. Tuttavia, è possibile per il per essere modificato da un altro filo non utilizza lo stesso metodo. L'approccio corretto sarebbe quello di utilizzare

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

Il codice sopra bloccherebbe tutte le discussioni tentativo di modificare di modificare l'elenco fino al blocco sincronizzato ha completato.

In pratica, il vantaggio di metodi sincronizzati oltre blocchi sincronizzati è che sono più idiota resistenti; perché non si può scegliere un oggetto arbitrario per agganciare, non è possibile abusare la sintassi metodo sincronizzato per fare cose stupide come blocco su una stringa letterale o bloccaggio sul contenuto di un campo mutabile che viene cambiato da sotto i fili.

D'altra parte, con i metodi sincronizzati non è possibile proteggere la serratura da ottenere acquisita da qualsiasi filo che può ottenere un riferimento all'oggetto.

Così, attraverso sincronizzato come modificatore sui metodi è meglio a proteggere i cow-orkers da farsi male, durante l'utilizzo di blocchi sincronizzati in combinazione con gli oggetti di blocco finale privato è meglio a proteggere il proprio codice dai cow-Lavoratori.

Da un Java sintesi specifica: http://www.cs.cornell.edu/andru/javaspec/17 .doc.html

  

L'istruzione sincronizzato (§14.17) calcola un riferimento ad un oggetto;   esso tenta di eseguire un'azione di blocco su quell'oggetto e non fa   procedere ulteriormente fino a quando l'azione di blocco è stato completato con successo. ...

     

Un metodo sincronizzato (§8.4.3.5) esegue automaticamente un'azione di blocco   quando viene richiamato; il suo corpo non viene eseguito fino a quando l'azione serratura ha   completato con successo. Se il metodo è un metodo di istanza , si   blocca la serratura associata con l'istanza per cui è stato richiamato   (Cioè, l'oggetto che verrà noto come questo durante l'esecuzione di   il corpo del metodo). Se il metodo è statico , si blocca il   serratura associata all'oggetto classe che rappresenta la classe   quale è definito il metodo. ...

In base a queste descrizioni, direi risposte più precedenti sono corrette, e un metodo sincronizzato potrebbe essere particolarmente utile per i metodi statici, dove altrimenti avrebbero dovuto capire come ottenere l'oggetto "Class che rappresenta la classe in cui il metodo è stato definito ".

Edit: Ho inizialmente pensato questi erano citazioni della specifica Java vero e proprio. Chiarito che questa pagina è solo un sommario / spiegazione della specifica

TLDR; Né usare il modificatore synchronized né l'espressione synchronized(this){...} ma synchronized(myLock){...} dove myLock è un campo istanza possesso di un oggetto privato

.

La differenza tra l'utilizzo del modificatore synchronized sulla dichiarazione metodo e l'espressione synchronized(..){ } nel corpo del metodo sono questo:

  • Il modificatore synchronized specificato sulla firma del metodo
    1. è visibile nel JavaDoc generato,
    2. è programmaticamente determinabile tramite riflessione quando si verifica il modificatore di un metodo per la Modifier.SYNCHRONIZED ,
    3. richiede meno di battitura e rientro rispetto al synchronized(this) { .... }, e
    4. (a seconda del vostro IDE) è visibile nel completamento classe di contorno e il codice,
    5. utilizza l'oggetto this come blocco quando dichiarata metodo non statico o classe contenitrice quando dichiarato in un metodo statico.
  • L'espressione synchronized(...){...} consente
    1. solo sincronizzare l'esecuzione di parti del corpo di un metodo,
    2. da utilizzare all'interno di un costruttore o un ( statica ) blocco di inizializzazione,
    3. per scegliere l'oggetto serratura che controlla l'accesso sincronizzato.

Tuttavia, utilizzando il modificatore synchronized o synchronized(...) {...} con this come oggetto di blocco (come nel synchronized(this) {...}), hanno lo stesso inconveniente. Entrambi usano essa la propria istanza come l'oggetto di blocco per la sincronizzazione su. Questo è pericoloso perché non solo l'oggetto stesso, ma qualsiasi altro oggetto esterno / codice che contiene un riferimento a tale oggetto può anche usare come un blocco di sincronizzazione con effetti collaterali potenzialmente gravi (riduzione delle prestazioni e deadlock ).

pratica Pertanto migliore è né usare il modificatore synchronized né l'espressione synchronized(...) unitamente this come oggetto di blocco, ma un oggetto di blocco privato a questo scopo. Ad esempio:

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
        }
    }
}

È inoltre possibile utilizzare più oggetti di blocco ma particolare attenzione deve essere presa per assicurare che questo non si traduca in deadlock quando utilizzato nidificato.

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
        }
    }
}

Credo che questa domanda è la differenza tra thread-safe Singleton e l'inizializzazione differita con doppio controllo chiusura . Ho sempre riferimento a questo articolo quando ho bisogno di attuare alcune Singleton specifico.

Bene, questa è una 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; 
  } 
} 
  

Pro:

     
      
  1. inizializzazione ritardata è possibile.

  2.   
  3. E 'sicuro thread.

  4.   
     

Contro:

     
      
  1. getInstance () viene sincronizzato in modo che provoca un rallentamento delle prestazioni come più thread non può accedere simultaneamente.
  2.   

Questo è un inizializzazione differita con doppio controllo chiusura :

// 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; 
  } 
} 
  

Pro:

     
      
  1. inizializzazione ritardata è possibile.

  2.   
  3. E 'anche thread-safe.

  4.   
  5. Performance ridotta a causa della parola chiave sincronizzato è superata.

  6.   
     

Contro:

     
      
  1. La prima volta, può influire sulle prestazioni.

  2.   
  3. Come contro. del metodo della doppia chiusura controllo è sopportabile in modo che possa essere   utilizzato per applicazioni multi-threaded ad alte prestazioni.

  4.   

Si prega di fare riferimento a questo articolo per ulteriori dettagli:

https://www.geeksforgeeks.org/java- Singleton-design-pattern-pratiche-examples /

Sincronizzazione con fili. 1) MAI usare sincronizzato (this) in un filo non funziona. Sincronizzazione con (questo) utilizza il thread corrente come oggetto thread bloccaggio. Dal momento che ogni filo è indipendente dagli altri fili, non v'è coordinamento di sincronizzazione. 2) Test di spettacolo codice in Java 1.6 su Mac la sincronizzazione metodo non funziona. 3) sincronizzato (lockObj) dove lockObj è un oggetto condiviso comune di tutte le discussioni sincronizzazione su di essa funzionerà. 4) ReenterantLock.lock () e .unlock lavoro (). Vedere tutorial Java per questo.

Il codice seguente mostra questi punti. Esso contiene anche il vettore thread-safe che verrebbe sostituito ArrayList, per dimostrare che molte discussioni aggiunta in un vettore non perdono alcuna informazione, mentre lo stesso con un ArrayList può perdere informazioni. 0) il codice attuale mostra una perdita di informazioni a causa di condizioni di gara A) Commento l'attuale etichetta linea A, e il commento dalla linea A di sopra di essa, quindi eseguire, metodo perde i dati, ma non dovrebbe. B) Reverse fase A, B e rimuovere il commento // blocco finale}. Quindi eseguire per vedere i risultati senza perdita di dati C) Commentare B, rimuovere il commento C. Run, vedere Sincronizzazione a (questo) perde i dati, come previsto. Non hanno il tempo di completare tutte le varianti, spero che questo aiuta. Se la sincronizzazione su (questo), o le opere di sincronizzazione metodo, si prega di indicare quale versione di Java e il sistema operativo hai provato. Grazie.

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top