Simultaneidade, BlockingQueues (Java 7) - 1

"Olá, amigo!"

"Olá, Kim!"

"Hoje, vou falar sobre simultaneidade."

" Simultaneidade é uma biblioteca de classes Java que inclui classes especiais que foram otimizadas para trabalhar com vários encadeamentos. Este é um tópico muito interessante e extenso. Mas hoje vamos apenas obter uma introdução. O pacote é chamado java.util. pacote simultâneo. Vou falar sobre algumas classes interessantes."

" Tipos atômicos. "

"Você já sabe que mesmo count++ não é uma operação thread-safe. Quando uma variável é incrementada em 1, na verdade, ocorrem três operações. Como resultado, pode haver um conflito quando a variável é alterada."

"Sim, Ellie me disse não faz muito tempo:"

Tópico 1 Tópico 2 Resultado
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

"Exatamente. Então Java adicionou tipos de dados para executar essas operações como um, ou seja, atomicamente (um átomo é indivisível)."

"Por exemplo, Java tem AtomicInteger, AtomicBoolean, AtomicDouble etc."

"Suponha que precisamos criar uma classe «contador»:"

Exemplo
class Counter
{
 private int c = 0;

 public void increment()
 {
  c++;
 }

 public void decrement()
 {
  c--;
 }

 public int value()
 {
  return c;
 }
}

"Como você faria objetos desta classe thread-safe?"

"Bem, eu faria todos os métodos sincronizados e pronto:"

Exemplo
class synchronized Counter
{
 private int c = 0;

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

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

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

"Bom trabalho. Mas como seria se usássemos tipos atômicos:"

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

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

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

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

"Sua classe e minha classe funcionam da mesma maneira, mas a classe com um AtomicInteger funciona mais rápido."

"Bem, é uma pequena diferença?"

"Sim. Com base na minha experiência, sempre recomendo começar com sincronizado. Somente quando todo o código do aplicativo tiver sido escrito e o processo de otimização tiver começado, você deve começar a reescrever o código para usar os tipos atômicos. Mas, em qualquer caso, eu queria que você saber que tais tipos existem. Mesmo que você não os use ativamente, sempre há uma chance de encontrar o código onde eles são usados."

"Eu concordo. Isso faz sentido."

"A propósito, você notou que os tipos atômicos não são imutáveis ? Em contraste com a classe Integer padrão , AtomicInteger contém métodos para alterar seu estado interno."

"Entendi. Assim como String e StringBuffer ."

"Sim algo assim."

" Coleções thread-safe " .

"Como exemplo de tal coleção, posso apresentar o ConcurrentHashMap. Como você tornaria o HashMap thread-safe?"

"Tornar todos os seus métodos sincronizados?"

"Claro, mas agora imagine que você tem um SynchronizedHashMap e dezenas de threads acessando-o. E cem vezes por segundo uma nova entrada é adicionada ao mapa e, no processo, todo o objeto é bloqueado para leitura e gravação."

"Bem, esta é a abordagem padrão. O que você pode fazer?"

"Os criadores de Java criaram algumas coisas legais."

"Primeiro, eles armazenam dados em um ConcurrentHashMap em um único bloco, mas os dividem em partes chamadas 'buckets'. E quando alguém altera os dados em um ConcurrentHashMap, bloqueamos apenas o bucket que está sendo acessado, em vez do objeto inteiro. Em outros palavras, muitos segmentos podem mudar o objeto simultaneamente."

"Em segundo lugar, você se lembra que não pode iterar sobre os elementos da lista/mapa e alterar a lista ao mesmo tempo? Esse código lançará uma exceção:"

Não itere sobre os elementos de uma coleção em um loop e altere-os simultaneamente
HashMap<String, Integer> map = new HashMap<String, Integer>();

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

"Mas no ConcurrentHashMap, você pode:"

Não itere sobre os elementos de uma coleção em um loop e altere-os simultaneamente"
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();

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

"O pacote concorrente tem muitas vantagens. Só precisamos entender muito bem essas classes para utilizá-las."

"Entendo. Obrigado, Kim. Estas aulas são realmente interessantes. Espero um dia dominá-las como um virtuoso."