Concurență, BlockingQueues (Java 7) - 1

"Bună, Amigo!"

"Bună, Kim!"

„Astăzi, am să vă povestesc despre concurență”.

Concurrency este o bibliotecă de clase Java care include clase speciale care au fost optimizate pentru lucrul din mai multe fire. Acesta este un subiect foarte interesant și amplu. Dar astăzi vom primi doar o introducere. Pachetul se numește java.util. pachet concomitent. Vă voi povesti despre câteva cursuri interesante."

Tipuri atomice ” .

„Știți deja că chiar și count++ nu este o operație sigură pentru fire. Când o variabilă este incrementată cu 1, au loc de fapt trei operații. Ca urmare, poate exista un conflict atunci când variabila este schimbată.”

„Da, Ellie mi-a spus nu de mult:”

Firma 1 Firma 2 Rezultat
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

"Exact. Apoi Java a adăugat tipuri de date pentru a efectua aceste operații ca unul singur, adică atomic (un atom este indivizibil)."

„De exemplu, Java are AtomicInteger, AtomicBoolean, AtomicDouble etc.”

„Să presupunem că trebuie să facem o clasă „contor”:”

Exemplu
class Counter
{
 private int c = 0;

 public void increment()
 {
  c++;
 }

 public void decrement()
 {
  c--;
 }

 public int value()
 {
  return c;
 }
}

„Cum ați face obiectele din această clasă sigure pentru fire?”

„Ei bine, aș face toate metodele sincronizate și aș termina cu el:”

Exemplu
class synchronized Counter
{
 private int c = 0;

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

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

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

„Bună treabă. Dar cum ar arăta dacă am folosi tipuri atomice:”

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

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

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

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

„Clasa ta și clasa mea funcționează ambele la fel, dar clasa cu un AtomicInteger funcționează mai repede.”

— Ei bine, este o mică diferență?

"Da. Pe baza experienței mele, recomand întotdeauna să conduci cu sincronizat. Numai când tot codul aplicației a fost scris și procesul de optimizare a început ar trebui să începi să rescrii codul pentru a folosi tipurile atomice. Dar, în orice caz, te-am dorit să știi că există astfel de tipuri. Chiar dacă nu le folosești în mod activ, există întotdeauna șansa să dai de codul în care sunt folosite."

— Sunt de acord. Asta are sens.

"Apropo, ai observat că tipurile atomice nu sunt imuabile ? Spre deosebire de clasa standard Integer , AtomicInteger conține metode pentru schimbarea stării sale interne."

„Am înțeles. La fel ca și String și StringBuffer ”.

"Da cam asa ceva."

Colecții sigure pentru fire.

„Ca exemplu de astfel de colecție, pot să vă prezint ConcurrentHashMap. Cum ați face HashMap sigur pentru fire?”

— Să-și sincronizeze toate metodele?

"Sigur, dar acum imaginați-vă că aveți un astfel de SynchronizedHashMap și zeci de fire care îl accesează. Și de o sută de ori pe secundă o nouă intrare este adăugată pe hartă și, în acest proces, întregul obiect este blocat pentru citire și scriere."

"Ei bine, aceasta este abordarea standard. Ce poți face?"

„Creatorii lui Java au venit cu câteva lucruri interesante.”

„În primul rând, ei stochează datele într-un ConcurrentHashMap într-un singur bloc, dar le împart în părți numite „bucket-uri”. Și când cineva schimbă datele într-un ConcurrentHashMap, atunci blocăm doar găleata care este accesată, mai degrabă decât întregul obiect. cuvinte, multe fire pot schimba obiectul simultan.”

"În al doilea rând, îți amintești că nu poți să itera elementele listei/hărții și să schimbi lista în același timp? Un astfel de cod va arunca o excepție:"

Nu repetați elementele unei colecții într-o buclă și schimbați-o simultan
HashMap<String, Integer> map = new HashMap<String, Integer>();

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

„Dar în ConcurrentHashMap, puteți:”

Nu repetați elementele unei colecții într-o buclă și schimbați-o simultan"
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();

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

„Pachetul concurent are multe avantaje. Trebuie doar să înțelegem foarte bine aceste clase pentru a le folosi.”

— Înțeleg. Mulțumesc, Kim. Sunt cursuri cu adevărat interesante. Sper că într-o zi le voi stăpâni ca un virtuoz.