Concorrenza, BlockingQueues (Java 7) - 1

"Ciao, Amico!"

"Ciao Kim!"

"Oggi vi parlerò della concorrenza."

" La concorrenza è una libreria di classi Java che include classi speciali che sono state ottimizzate per il lavoro da più thread. Questo è un argomento molto interessante ed esteso. Ma oggi avremo solo un'introduzione. Il pacchetto si chiama java.util. pacchetto simultaneo. Ti parlerò di un paio di classi interessanti."

" Tipi atomici " .

"Sapete già che anche count++ non è un'operazione thread-safe. Quando una variabile viene incrementata di 1, vengono effettivamente eseguite tre operazioni. Di conseguenza, potrebbe verificarsi un conflitto quando la variabile viene modificata."

"Sì, Ellie mi ha detto non molto tempo fa:"

Discussione 1 Filo 2 Risultato
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

"Esattamente. Quindi Java ha aggiunto i tipi di dati per eseguire queste operazioni come uno, cioè atomicamente (un atomo è indivisibile)."

"Ad esempio, Java ha AtomicInteger, AtomicBoolean, AtomicDouble , ecc."

"Supponiamo di dover creare una classe «contro»:"

Esempio
class Counter
{
 private int c = 0;

 public void increment()
 {
  c++;
 }

 public void decrement()
 {
  c--;
 }

 public int value()
 {
  return c;
 }
}

"Come renderesti sicuri i thread degli oggetti di questa classe?"

"Bene, vorrei sincronizzare tutti i metodi e farla finita:"

Esempio
class synchronized Counter
{
 private int c = 0;

 public synchronized void increment()
 {
  c++;
 }

 public synchronized void decrement()
 {
  c--;
 }

 public synchronized int value()
 {
  return c;
 }
}

"Ottimo lavoro. Ma come sarebbe se usassimo i tipi atomici:"

Esempio
class AtomicCounter
{
 private AtomicInteger c = new AtomicInteger(0);

 public void increment()
 {
  c.incrementAndGet();
 }

 public void decrement()
 {
  c.decrementAndGet();
 }

 public int value()
 {
  return c.get();
 }
}

"La tua classe e la mia classe funzionano entrambe allo stesso modo, ma la classe con un AtomicInteger funziona più velocemente."

"Beh, è ​​una piccola differenza?"

"Sì. Sulla base della mia esperienza, consiglio sempre di condurre con sincronizzato. Solo quando tutto il codice dell'applicazione è stato scritto e il processo di ottimizzazione è iniziato dovresti iniziare a riscrivere il codice per utilizzare i tipi atomici. Ma in ogni caso, volevo che tu per sapere che tali tipi esistono. Anche se non li usi attivamente, c'è sempre la possibilità che ti imbatti nel codice dove vengono utilizzati.

"Sono d'accordo. Ha senso."

"A proposito, hai notato che i tipi atomici non sono immutabili ? A differenza della classe Integer standard , AtomicInteger contiene metodi per modificare il suo stato interno."

"Ricevuto. Proprio come String e StringBuffer ."

"Sì, qualcosa del genere."

" Raccolte thread-safe. "

"Come esempio di una tale raccolta, posso presentare ConcurrentHashMap. Come renderesti HashMap thread-safe?"

"Rendere sincronizzati tutti i suoi metodi?"

"Certo, ma ora immagina di avere una tale SynchronizedHashMap e dozzine di thread che vi accedono. E cento volte al secondo una nuova voce viene aggiunta alla mappa, e nel processo l'intero oggetto è bloccato per la lettura e la scrittura."

"Bene, questo è l'approccio standard. Cosa puoi fare?"

"I creatori di Java hanno escogitato alcune cose interessanti."

"In primo luogo, memorizzano i dati in una ConcurrentHashMap in un singolo blocco, ma li dividono in parti chiamate 'bucket'. E quando qualcuno modifica i dati in una ConcurrentHashMap, blocchiamo solo il bucket a cui si accede, anziché l'intero oggetto. In altri parole, molti thread possono cambiare l'oggetto contemporaneamente."

"In secondo luogo, ti ricordi che non puoi scorrere gli elementi dell'elenco/mappa e modificare l'elenco allo stesso tempo? Tale codice genererà un'eccezione:"

Non eseguire iterazioni sugli elementi di una raccolta in un ciclo e modificarla contemporaneamente
HashMap<String, Integer> map = new HashMap<String, Integer>();

for (String key: map.keySet())
{
 if (map.get(key) == 0)
  map.remove(key);
}

"Ma in ConcurrentHashMap, puoi:"

Non eseguire iterazioni sugli elementi di una raccolta in un ciclo e modificarla contemporaneamente"
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();

for (String key: map.keySet())
{
 if (map.get(key) == 0)
  map.remove(key);
}

"Il pacchetto concurrent ha molti vantaggi. Dobbiamo solo comprendere molto bene queste classi per poterle utilizzare."

"Capisco. Grazie, Kim. Queste sono lezioni davvero interessanti. Spero che un giorno le padroneggerò come un virtuoso."