Devo sempre fazer o meu java-código thread-safe, ou para desempenho de razões fazê-lo apenas quando necessário?

StackOverflow https://stackoverflow.com/questions/234341

Pergunta

Se eu criar classes, que são utilizados no momento apenas em um único segmento, devo fazê-los thread-safe, mesmo que eu não preciso que no momento? Poderia ser acontecer, que eu depois usar essa classe em vários segmentos, e naquele tempo eu poderia obter condições de corrida e pode ter um tempo difícil encontrá-los se eu não fez a classe thread-safe em primeiro lugar. Ou eu deveria fazer a classe não thread-safe, para um melhor desempenho? Mas otimização prematura é mau.

Ao contrário perguntou: Devo fazer minhas aulas de thread-safe, se necessário (se usado em vários segmentos, caso contrário não) ou devo otimizar esta questão, então, necessário (se eu ver que os come sincronização até uma parte importante do tempo de processamento) ?

Se eu escolher uma das duas maneiras, existem métodos para reduzir as desvantagens? Ou existe uma terceira possibilidade, que eu deveria usar?

Editar : Eu dou a razão esta questão veio à minha mente. Na nossa empresa temos escrito uma forma muito simples de gerenciamento de usuário que grava os dados em propriedade-arquivos. Usei-o em um web-app e depois de algum trabalho nele eu tenho erros estranhos, que o gerenciamento de usuários esqueceu propriedades de usuários (incluindo nome e senha) e papéis. Isso foi muito chato, mas não consistentemente reprodutível, então eu acho que foi condição de corrida. Desde que eu sincronizado todos os métodos de leitura e escrita de / no disco, o problema desapareceu. Então eu pensei, que eu provavelmente poderia ter sido evitado todos os problemas, se tivéssemos escrito a classe com a sincronização em primeiro lugar?

EDIT 2 : como eu olhar sobre as pontas dos Pragmatic Programmer, vi a dica # 41: Sempre Design for Concorrência. Isso não quer dizer que todo o código deve ser thread-safe, mas ele diz que o projeto deve ter a concorrência em mente.

Foi útil?

Solução

Iniciar a partir dos dados. Decidir qual os dados são explicitamente compartilhado e protegê-lo. Se de todo possível, encapsular o bloqueio com os dados. Use coleções simultâneas thread-safe pré-existente.

Sempre que possível, usar objetos imutáveis. Tornar os atributos final, definir seus valores nos construtores. Se você precisa de "mudança", os dados consideram retornar uma nova instância. objetos imutáveis ??não precisa de bloqueio.

Para objetos que não são compartilhadas ou fios confinado, não gastam tempo fazendo-thread-safe.

Documento as expectativas no código. As anotações JCIP são a melhor escolha pré-definidos disponíveis.

Outras dicas

Eu costumava tentar fazer tudo o thread-safe - então eu percebi que o próprio significado de "thread-safe" depende da utilização. Muitas vezes você simplesmente não pode prever que o uso, eo chamador irá Have para agir de qualquer maneira para usá-lo de uma forma thread-safe.

Estes dias eu escrevo quase tudo assumindo única threading, e colocar enfiar conhecimento nas seleto poucos lugares onde importa.

Dito isto, eu faço também (quando apropriado) criar tipos imutáveis, que são naturalmente passíveis de multi-threading -., Além de ser mais fácil raciocinar sobre em geral

Siga o prinicple de "o mais simples possível, mas não mais simples." Na ausência de uma exigência, você não deve torná-los thread-safe. Fazer isso seria especulativo, e provavelmente desnecessário. programação thread-safe adiciona muito mais complexidade às suas aulas, e provavelmente irá torná-los menos eficaz devido a tarefas de sincronização.

A menos que explicitamente declarado que um objeto é thread-safe, a expectativa é de que não é.

Eu pessoalmente só o design classes que são "thread-safe" quando necessário - no princípio de otimizar apenas quando necessário. Sun parecem ter ido da mesma forma com o exemplo de classes de coleções thread único.

No entanto, existem alguns princípios boas que irão ajudá-lo de qualquer forma, se você decidir mudar:

  1. O mais importante: Pense antes de sincronizar. Eu tinha um colega, uma vez que usado para sincronizar coisas "apenas no caso - afinal sincronizado deve ser melhor, certo?" Isso é errado, e foi uma causa de vários erros de impasse.
  2. Se seus objetos podem ser imutável, torná-los imutáveis. Isto não só ajudará com threading, vai ajudá-los a ser usado com segurança em conjuntos, como chaves para Mapas etc
  3. Mantenha os objetos mais simples possível. Cada um deve, idealmente, só fazem um trabalho. Se você alguma vez encontrar você pode querer acesso Sincronizar para metade dos membros, então você possivelmente deve dividir o objeto em dois.
  4. Saiba java.util.concurrent e usá-lo sempre que possível. Seu código será melhor, mais rápido e mais seguro do que o seu (ou mina) em 99% dos casos.
  5. Leia Programação Concorrente em Java , é ótimo!

Assim como uma observação lateral: Sincronização = Thread-segurança. Mesmo que você não pode simultaneamente modificar dados, mas você pode lê-lo simultaneamente. Portanto, manter o modelo de Java Memória em mente onde sincronização significa fazer dados confiáveis ??disponíveis em todos os segmentos, não só proteger a modificação concorrente dele.

E sim, na minha opinião thread-segurança tem de construído em direito desde o início e isso depende da lógica da aplicação, se você precisa de manipulação de concorrência. Nunca assuma nada e mesmo se o teste parece estar bem, condições de corrida estão dormindo cães.

Eu encontrei os JCIP anotações muito útil para declarar que as classes são thread-safe. Minha equipe anota nossas aulas como @ThreadSafe , < a href = "http://www.javaconcurrencyinpractice.com/annotations/doc/net/jcip/annotations/NotThreadSafe.html" rel = "nofollow noreferrer"> @ NotThreadSafe ou @ Imutável . Isto é muito mais clara do que ter que ler Javadoc, e FindBugs nos ajuda a encontrar violações do @Immutable e @ GuardedBy contratos também.

Você deve absolutamente saber quais segmentos do seu código será multi-threaded e que não vai.

Sem ser capaz de se concentrar na área de multithreadedness em uma seção pequena, controlável, você não vai ter sucesso. As partes do seu aplicativo que são necessidade de multi-threaded para ser ido mais cuidadosamente, totalmente analisado, compreendido e adaptado para um ambiente multi-threaded.

O resto não e, portanto, tornando-thread-safe seria um desperdício.

Por exemplo, com o GUI swing, Sun apenas decidi que nada disso seria multi-threaded.

Oh, e se alguém usa suas classes -. Cabe a eles para garantir que se está em uma seção de rosca, em seguida, torná-lo threadsafe

Sun inicialmente saiu com coleções Threadsafe (apenas). o problema é, threadsafe não pode ser feita un-threadsafe (para fins de desempenho). Então agora eles saíram com versões un-threadsafe com wrappers para torná-los threadsafe. Para a maioria dos casos, as embalagens são desnecessários - supor que, a menos que você está criando os fios você mesmo, que sua classe não tem que ser threadsafe - mas documentá-lo nos javadocs

.

Aqui está a minha abordagem pessoal:

  • objetos marca e estrutura de dados imutável sempre que puder. Isso é uma boa prática, em geral, e é automaticamente thread-safe. Problema resolvido.
  • Se você tem que fazer um mutável objeto, em seguida, normalmente não se incomode tentando fazê-lo o segmento de seguros . O raciocínio para isso é simples: quando você tem estado mutável, em seguida, bloqueio / controle não pode ser manuseado com segurança por uma única classe. Mesmo se você sincronizar todos os métodos, isso não garante a segurança do thread. E se você adicionar a sincronização para um objeto que só nunca é usado em um contexto single-threaded, então você acabou de adicionar sobrecarga desnecessária. Então, assim como você pode deixá-lo até o chamador / usuário para implementar qualquer sistema de bloqueio é necessário.
  • Se você fornecer um maior API pública de nível, em seguida, implementar tudo o bloqueio é necessário para fazer o seu segmento seguro API . Para a funcionalidade de nível superior a sobrecarga de segurança do segmento é bastante trivial, e seus usuários vão certamente obrigado. Uma API com a semântica de concorrência complicados que os usuários precisam para o trabalho em torno não é uma boa API!

Esta abordagem tem me servido bem ao longo do tempo: você pode precisar fazer a exceção ocasional, mas em média é um lugar muito bom para começar

Se você quiser seguir o que a Sun fez na API Java, você pode dar uma olhada nas classes de coleção. Muitas classes de coleção comum não são thread-safe, mas têm contrapartidas thread-safe. De acordo com Jon Skeet (ver comentários), muitas das classes Java foram originalmente thread-safe, mas eles não estavam se beneficiando desenvolvedores, por isso, algumas classes têm agora duas versões - um ser thread-safe e os outros não thread-safe

Meu conselho é não fazer thread-safe o código até que você tem que, como há alguma sobrecarga envolvida com thread-segurança. Eu acho que isso se enquadra na mesma categoria que a otimização -. Não fazê-lo antes que você tem a

Projeto separadamente as classes de usar de vários segmentos e documentos demais para ser usado a partir de apenas único segmento.

Single rosca queridos são muito mais fáceis de se trabalhar.

Separar a lógica multithreaded ajuda a fazer a sincronização correta.

"Sempre" é uma palavra muito perigosa no desenvolvimento de software ... escolhas como esta são "sempre" situacional.

Para evitar condições de corrida, de bloqueio em apenas um objeto - as descrições ler de condições de corrida tediosamente e você vai descobrir que cruzam-locks (condição de corrida é um equívoco - raça vem para parar lá) são sempre uma consequência de dois threads + tentando para fechamento em dois objetos +.

Faça todos os métodos sincronizados e fazer testes - para qualquer aplicativo do mundo real que realmente tem de lidar com os problemas de sincronização é um custo pequeno. O que eles não dizem é que a coisa toda não lockout em mesas de ponteiro de 16 bits ... em que ponto você é uh, ...

Basta manter o seu currículo hambúrguer flippin atual.

Se eu criar classes, que são usados ??no momento apenas em um único segmento, devo fazê-los thread-safe

Não é necessário para uma classe usada por um fio para, por si só thread-safe para o programa como um todo para ser thread-safe. Você pode seguramente compartilhar objetos de não classes "thread-safe" entre threads se eles são protegidos por sincronização apropriado. Assim, não há necessidade de fazer uma classe em si thread-safe, até que se torna aparente.

No entanto, multi-threading é a escolha fundamental (arquitetura) em um programa. É não é realmente algo a acrescentar como um pensamento depois . Então você deve saber desde o início que as classes precisam ser thread-safe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top