Паралелност, BlockingQueues (Java 7) - 1

„Здрасти, Амиго!“

„Здравей, Ким!“

„Днес ще ви разкажа за паралелността.“

" Concurrency е библиотека с класове на Java, която включва специални класове, които са оптимизирани за работа от множество нишки. Това е много интересна и обширна тема. Но днес просто ще ви представим. Пакетът се нарича java.util. паралелен пакет. Ще ви разкажа за няколко интересни класа."

" Атомни типове. "

„Вече знаете, че дори count++ не е безопасна за нишка операция. Когато една променлива се увеличи с 1, всъщност се извършват три операции. В резултат на това може да има конфликт, когато променливата се промени.“

„Да, Ели ми каза неотдавна:“

Тема 1 Нишка 2 Резултат
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

„Точно така. Тогава Java добави типове данни, за да изпълнява тези операции като едно, т.е. атомарно (един атом е неделим).“

„Например Java има AtomicInteger, AtomicBoolean, AtomicDouble и т.н.“

"Да предположим, че трябва да направим клас "контра":"

Пример
class Counter
{
 private int c = 0;

 public void increment()
 {
  c++;
 }

 public void decrement()
 {
  c--;
 }

 public int value()
 {
  return c;
 }
}

„Как бихте направor обекти от този клас безопасни за нишки?“

„Е, бих направил всички методи синхронизирани и готово с това:“

Пример
class synchronized Counter
{
 private int c = 0;

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

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

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

„Добра работа. Но How би изглеждало, ако използвахме атомни типове:“

Пример
class AtomicCounter
{
 private AtomicInteger c = new AtomicInteger(0);

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

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

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

„Вашият и моят клас работят по един и същи начин, но класът с AtomicInteger работи по-бързо.“

— Е, малка ли е разликата?

„Да. Въз основа на моя опит винаги препоръчвам да водите със синхронизирани. Едва когато целият code на приложението е написан и процесът на оптимизация е започнал, трябва да започнете да пренаписвате codeа, за да използвате атомарните типове. Но във всеки случай исках да ви да знаете, че съществуват такива типове. Дори и да не ги използвате активно, винаги има шанс да попаднете на code, където се използват."

"Съгласен съм. Това има смисъл."

"Между другото, забелязахте ли, че атомните типове не са неизменни ? За разлика от стандартния клас Integer , AtomicInteger съдържа методи за промяна на вътрешното му състояние."

„Разбрах. Точно като String и StringBuffer .“

— Да, нещо такова.

Колекции, безопасни за нишки.

„Като пример за такава колекция, мога ли да представя ConcurrentHashMap. Как бихте направor HashMap нишково безопасен?“

„Да направя всичките му методи синхронизирани?“

„Разбира се, но сега си представете, че имате една такава SynchronizedHashMap и десетки нишки, които имат достъп до нея. И сто пъти в секунда нов запис се добавя към картата и в процеса целият обект е заключен за четене и запис.“

„Е, това е стандартният подход. Какво можете да направите?“

„Създателите на Java измислиха няколко страхотни неща.“

„Първо, те съхраняват данни в ConcurrentHashMap в един блок, но ги разделят на части, наречени „кофи“. И когато някой промени данни в ConcurrentHashMap, ние заключваме само кофата, до която има достъп, а не целия обект. думи, много нишки могат да променят обекта едновременно."

"Второ, помните ли, че не можете да обхождате елементите на списъка/картата и да променяте списъка едновременно? Такъв code ще хвърли изключение:"

Не итерирайте елементите на колекция в цикъл и едновременно с това я променяйте
HashMap<String, Integer> map = new HashMap<String, Integer>();

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

„Но в ConcurrentHashMap можете:“

Не итерирайте елементите на колекция в цикъл и едновременно с това я променяйте"
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();

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

„Едновременният пакет има много предимства. Просто трябва да разберем много добре тези класове, за да ги използваме.“

„Разбирам. Благодаря, Ким. Това са наистина интересни часове. Надявам се, че някой ден ще ги овладея като виртуоз.“