Java memory model primary ref. - faq

217 visualizações

Publicada em

Java Memory Model

Language: Portuguese

Based upon http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

Publicada em: Educação
0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
217
No SlideShare
0
A partir de incorporações
0
Número de incorporações
2
Ações
Compartilhamentos
0
Downloads
1
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Java memory model primary ref. - faq

  1. 1. Java Memory Model – FAQ Table of Contents O que é ?...............................................................................................................................................1 Reordenação de Operações:..................................................................................................................2 Conceito de sincronização:...................................................................................................................3 Keyword 'Final':...................................................................................................................................4 Keyword 'Volatile':...............................................................................................................................5 O que é ? Em primeiro lugar, para efeitos de contexto, estamos a falar de sistemas com vários processadores integrados em si mesmo. Tipicamente, estes sistemas contém vários níveis de cache de memória, algo que melhora significativamente a performance de acesso a dados. No entanto, com adição destas caches, algumas questões têm de ser tratadas com cautela. Por exemplo: • O que acontece quando dois processadores apontam para a mesma localização de memória, ao mesmo tempo; • Em que condições serão, os dois, capazes de visualizar o mesmo conteudo nessa mesma localização de memória; Basicamente, se analisarmos ao pormenor diversos processadores, seriamos capazes de perceber que, consoante o cpu/modelo em causa, estaríamos na presença de um modelo de memória que poderia ser muito bom ou muito mau. No entanto, enquanto programadores de linguagens de alto nível, a abstração é tão grande que nunca se deve relacionar conceitos de tão baixo nível com essas mesmas abstrações. Desta forma, a linguagem Java detém um modelo que descreve o comportamento adequado em situações de código multi-threading, bem como as Threads devem agir perante determinadas operações em memória. Descreve as relações existentes entre variáveis de um programa com os detalhes de baixo-nivel relativos à memória e processador.
  2. 2. Para ajudar nesta descrição e estabelecimento de regras relativamente ao modelo imposta pela linguagem Java, a mesma detém funcionalidades que procuram ajudar o programador a construir código concorrente sem erros: • Volatile e Final keywords; • Blocos synchronized; • etc.. Ao especificar este modelo de memoria, a linguagem Java assegura que todos os programas multi-threading executam corretamente em todas as arquiteturas. Reordenação de Operações: Por vezes, na execução de um programa, pode parecer que uma ou mais instruções estão a ser executadas numa ordem diferente daquela que está especificada pelo código fonte. Faz-se notar que, o compilador tem a liberdade de ordenar a execução de instruções caso entenda que as mesmas serão otimizadas se for feita uma reordenação. A reordenação pode ser feita por outras entidades que não o compilador. Por exemplo, quando é feita uma escrita para uma variável a e depois para uma variável b, e o valor de 'b' não depende do valor de 'a', então o compilador pode reordenar estas instruções como bem entender. Reordenações podem ter efeitos nefastos num programa multi-threading, porque tipicamente , neste tipo de programas Threads estão interessadas em saber o que outras Threads andam a fazer. Neste caso, para garantir o correto funcionamento, mesmo sobre reordenações de operações, é aplicado o conceito de sincronização.
  3. 3. Conceito de sincronização: O conceito de sincronização enquadra-se em diversos aspetos, sendo o mais conhecido, a exclusão-mútua. De uma forma geral, sincronização garante que, dados escritos anteriormente à execução de um bloco synchronized estarão visíveis para a Thread que detém esse “bloco” de uma forma previsível. Após sairmos desse bloco, libertamos o monitor, o mesmo é dizer, tornamos todas as mudanças feitas durante esse bloco em mudanças fixas e visíveis para as outras Threads. Antes de entrarmos num bloco, temos de adquirir o monitor, o mesmo é dizer que invalidamos o acesso a caches locais do cpu de forma a que as variáveis sejam obtidas através de acesso a memória principal. O modelo de memória introduz novos conceitos como read-field, write-field, lock, unlock, e novas operações sobre Threads como join e start. Introduz ainda o conceito de relação entre operações denominado por happens-before. Quando duas operações estabelecem esta relação entre si, entenda-se 'a' happens-before 'b', significa que a operação 'a' irá sempre, mesmo que reordenada, ser executada antes da operação 'b', bem como os seus resultados estarão visíveis perante o inicio de 'b'. Algo que é completamente errado fazer é o seguinte padrão de código: • synchronized (new Object()) {….} O compilador irá remover por completo esta forma de “sincronização”, uma vez que é inteligente o suficiente para perceber que nunca outra Thread irá tentar adquirir um lock relativo a um monitor que não é referenciado por nenhuma referência. É importante ter consciência de que, duas Threads têm de sincronizar relativamente ao mesmo monitor, por forma a estabelecer esta relação de happens-before.
  4. 4. Keyword 'Final': Dentro do modelo de memória Java, a keyword final e o comportamtento adjacente a esta, explica o facto de classes imutáveis serem sempre Thread-Safe. Porquê ? Vejamos então o que significa ser 'final'. Quando um campo é 'final', esse mesmo campo será visível para todas as Threads, mesmo sem qualquer sincronização implementada, após um construção de objecto bem realizada. Por bem construido, entende-se que todas as funções de construção de um objecto são apenas e só realizadas dentro do construtor. Veja-se o seguinte exemplo: Qualquer Thread que invoque o método reader, conseguirá visualizar f.x como tendo o valor de 3. O mesmo não se pode dizer sobre y. Assim, conclui-se que, uma classe que tenha uma construção bem realizada, bem como todos os seus campos serem 'final', é uma classe immutable e sempre Thread-Safe, pois os seus campos apresentarão sempre os valores armazenados sempre que forem invocados por outras Threads. Faz-se notar que, mesmo uma classe ser completamente Thread-Safe não remove a necessidade de sincronização por parte de Threads que queiram ter acesso a esta. Por exemplo, não existe forma de garantir que a referência para o objecto imutável será correctamente visualizado por uma segunda Thread. class FinalFieldExample { final int x; int y; static FinalFieldExample f; public FinalFieldExample() { x = 3; y = 4; } static void writer() { f = new FinalFieldExample(); } static void reader() { if (f != null) { int i = f.x; int j = f.y; } } }
  5. 5. Keyword 'Volatile': Um mecanismo que foi implementado para possibilitar a comunicação de estados entre Threads. Cada leitura de um campo volatile irá sempre obter o último valor escrito até à data por qualquer Thread. Proíbe o compilador e o runtime de armazenarem estes valores em registos. Em vez disso, são sempre escritos na memória principal. Faz-se notar um grande e importante aspeto que nem sempre é evidenciado pela literatura acerca de variáveis volatile. O modelo de memória aplica uma enorme restrição no que toca à escrita e leitura de variáveis volatile. Entenda-se que: • Escrita sobre um volatile => release de um monitor; • Leitura de um volatile => adquire de um monitor; (=> - “equivale a”) Isto acontece porque, tudo o que é visível para uma Thread no dado momento em que a mesmo escrever sobre um volatile, também tem de ser visível para uma próxima Thread que vá ler o volatile. No seguinte exemplo, temos então a garantia de visualizar um campo que não é final apenas porque estamos perante a escrita de um valor numa variável volatile. É importante perceber que, ambas as Threads têm de aceder à mesma variável volatile de forma a estabelecer a propriedade Happens-Before. class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() { if (v == true) { //uses x - guaranteed to see 42. } } }
  6. 6. Por Pedro Almeida. Baseado em: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

×