Muitos métodos static, é bom ou ruim?

45 respostas
mauricioadl

Pessoal, bom dia!

Tenho buscado muita informação sobre assuntos de funcionamento da jvm, gc, etc e fico cada vez mais confuso, ja que cada dia que passa descubro que sei quase nada de java. :?
Vamos a minha dúvida.

Sei que os métodos static são carregados no classloader e sei também que eles são mais rápidos, a minha dúvida é se uma aplicação grande tiver muitos métodos static em muitas classes o que realmente vai acontecer?
A aplicação será mais rápida por ter muitos métodos rápidos ou sera mais lenta por ter muitas informações carregadas e não usadas frequentemente?

Obrigado!

45 Respostas

johnny_quest

O que irá acontecer é de a aplicação utilizar muitos métodos estáticos é de se programar em estilo procedural, não tendo nada
de OO no código.

Se for uma aplicação bem pequena(tipo hello world) até pode ser mais rápido desenvolver, mas se for uma aplicação comercial séria, mesmo que pequena,
a manutenção disso se tornará um inferno de gambiarra. Assim, será um programa em java estilo C anos 70.

mauricioadl

Ola johnny quest obrigado pela resposta, mas a minha pergunta seria sobre o desempenho, ignorando o fato da modularização das classes e perda da OO.

sergiotaborda

mauricioadl:
Pessoal, bom dia!

Tenho buscado muita informação sobre assuntos de funcionamento da jvm, gc, etc e fico cada vez mais confuso, ja que cada dia que passa descubro que sei quase nada de java. :?
Vamos a minha dúvida.

Sei que os métodos static são carregados no classloader

Quem é carregado é a classe, não os métodos.

Não. Um método estático é igual de rápido que um não estático. Lembre-se que o compilador java já decidiu qual método será invocado.

Não.

A rapidez depende da jvm e do hardware e não se usa estático ou não-estático. Fora que usar muitos estaticos não é OOP e nos tempos modernos o uso descontrolado de de static é um anti-pattern. O static tem o seu papel para métodos da classe ( não do objeto) que são necessários em alguns padrões.

Em JVM modernas , sobretudo no hotstop criar e destruir objetos é quase grátis e não deve ser considerado um problema. Em java não vale fazer otimizações loucas porque isso engana a jvm que tem mecanismos de otimização dinamicos ( coisas que no C são comuns como iterar ao contrário, por exemplo) .

Deixe a JVM otimizar o codigo, ela é muito eficiente nisso. Mas para ela otimizar seu codigo deve ser bom, ter boa saude. O código é tão mais saudável quando menor o escopo das variáveis e mais OO for.

E

Uma das principais diferenças do C# em relação ao Java é que em Java todos os métodos que não são static são " virtuais " (ou seja, será chamado o método implementado pela classe do objeto, não o que está implementado pela classe que representa o tipo da variável.

Em C# você deve especificar tal comportamento explicitamente, já que o padrão é chamar o método implementado pela classe que representa o tipo da variável.

Isso, em tese, sempre seria mais lento (porque você precisaria acessar sempre um bloco de dados que em C++ se chama ‘vtable’), mas a JVM está avançada suficientemente hoje em dia para chamar diretamente o método correspondente à classe que representa o tipo da variável dependendo do grau de otimização que ela conseguiu alcançar ao executar seu programa, e essa ‘desvantagem’ do Java na prática não existe mais.

Ou seja, na prática a diferença entre um método “static” e outro normal é que em um método não static um parâmetro a mais é passado implicitamente (this), ou seja, é algo que não aumenta o tempo de execução de forma alguma.

Ou seja, deixar seu programa cheio de métodos “static” não vai melhorar o tempo de execução de forma alguma. É melhor usar “static” onde ele deve ser usado, não como uma forma ingênua de melhorar o desempenho.
Muitas vezes onde o tempo de execução “pega” é, por exemplo, em uma configuração errada do DNS :slight_smile:

E

Vou dar outro exemplo boboca.

O que é mais rápido (supondo que o log esteja desabilitado, que é o que deve ocorrer em produção) :
a) if (logger.isDebugEnabled()) { logger.debug("Logging in user " + user.getName() + " with id " + user.getId()); }
ou
b) logger.debug("Logging in user " + user.getName() + " with id " + user.getId());

Já vi gente que disse que a alternativa a) era mais lenta (porque tinha de ficar testando, e além disso um programa menor é mais rápido, não? ) e já vi gente que disse que tanto faz.

Entretanto, em Java a opção a) é que é mais rápida (se o log estiver desabilitado), porque mesmo que você não logue nada (que é o que ocorre na alternativa b) ) você ainda tem o trabalho de calcular os parâmetros.

Ou seja, na verdade não é tão simples dizer, só de olhar um programa, se ele vai ser mais rápido ou não.

ViniGodoy
Além disso, considere que:

a) Métodos estáticos são mais difíceis de usar em contextos de multiplas threads - o que pode ter um impacto significativamente ruim na performance;

b) Métodos estáticos não fazem polimorfismo -  que esse é um atributo da instância;

Finalmente, onde você anda lendo sobre performance?
Cuidado com os mitos, a internet está cheia deles.

Eles geralmente surgem do exagero de uma informação.

O que é mais lento num método estático em relação a um não estático (ou, mais precisamente, um método polimorfico, em relação a um não polimorfico) é a invocação, não a execução. Ou seja, é o tempo que o compilador leva entre a linha que chama o método, e a primeira linha desse mesmo método - em outras palavras, o tempo para “entrar” no método. E, em ambos os casos, esse tempo é extremamente pequeno, provavelmente, muito menor do que os comandos dentro do método levarão para executar.

Mesmo no caso do C++, onde a vtable não é otimizada em tempo de execução, culpar um método polimorfico pelo desempenho de execução  faz sentido em casos onde:

a) A aplicação é CPU Bound (ou seja, faz muitos cálculos e poucas operações de entrada/saída);

b) O método estático é uma das peças centrais do processamento, e está rodando num loop;

c) O tempo de execução do método estático é muito pequeno.

Aplicações matemáticas, como as de computação gráfica, meteorologia, ou bolsa de valores, podem vir a atingir esses três objetivos simultaneamente. Aplicações comerciais, raramente.

Recomendo fortemente que você leia os artigos do Brian Goetz, em especial, a série chamada Java theory and practice:
http://www.briangoetz.com/pubs.html

E

ViniGodoy:
Métodos estáticos são mais difíceis de usar em contextos de multiplas threads - o que pode ter um impacto significativamente ruim na performance;

Uma vez eu resolvi criar um método estático para formatar datas de acordo com um determinado padrão fixo de um SimpleDateFormat. O único problema é que o SimpleDateFormat não é thread-safe. (Eu não tinha lido as letras miúdas). Após bater a cabeça depois de alguns erros esporádicos muito estranhos, eu acabei descobrindo que:
a) Isso tinha sido registrado no Bug DataBase da Sun
b) e que a Sun (hoje Oracle) não ia resolver isso.

O método continuou estático, mas tive de usar um ThreadLocal para criar uma instância do SimpleDateFormat para cada thread. Isso foi muito chato de descobrir, e é um exemplo de que tipos de problemas podem ter métodos estáticos.

mauricioadl

Pessoal, muito obrigado a todos, foi de grande conhecimento.

entaglement, é bem comum ver esse método static de formatação de datas. Sincronizar esse método não resolveria o problema?

E

Resolver resolve, mas eu não gosto de sincronização porque sincronização = serialização, e se você serializar uma operação lenta (formatação de datas) ela pode se tornar um gargalo no sistema.

Dentro da medida do possível, deve-se evitar a sincronização, a menos que isso seja inevitável e você não tenha realmente uma boa alternativa (no meu caso, uma ThreadLocal resolvia bem meu problema, porque transformava o problema de sincronizar uma operação lenta (formatar uma data) no problema de sincronizar uma operação que em média é rápida (escolher no HashMap embutido no ThreadLocal o objeto correspondente à thread corrente).

B

Isso só vale se quando o método estático usa uma variável compartilhada (leia-se, externa ao método), não é Vini?

E

Tanto é que várias classes das versões mais antigas do JDK (como Hashtable, Vector e StringBuffer) têm sincronização implícita (se você olhar os fontes, há um monte de “synchronized” nessas classes) que foi removida nas versões mais modernas dessas classes (HashMap, ArrayList e StringBuilder).

J

Isso só vale se quando o método estático usa uma variável compartilhada (leia-se, externa ao método), não é Vini?

Acredito que sim, devido ao escopo… ou estou errado ???
Como sempre evitei métodos estáticos, fiquei na duvida se este código pode apresentar problema:

public static String converterDataString(Date cal, String formato) throws CoreException {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(formato);
			String dataStr = sdf.format(cal);
			return dataStr;
		} catch (Exception ex) {
			throw new CoreException("Erro em converterDataString.", ex);
		}
	}
mauricioadl

Pessoal, desculpe ficar “petulando” com duvidas idiotas. Por exemplo um método assim:

static Object outro = new ObjectQualquer();
public static ObjectQualquer fazAlgumaCoisa(Object parametro) {
// algumas operações 
return outro.fazAlqumaCoisa(parametro);
}

O exemplo é meio idiota, mas acho que vc vai entender.
Vamos supor que uma thread executa esse método e na linha 1 ela dorme e deixa a outra thread rodar, a outra executa o metodo tambem e encerra e volta para onde a primeira parou para continuar, o objeto outro teve sua informação alterada pela segunda thread e agora a informação dele ficou errada para a primeira que dormiu. o que vai acontecer? dar concurrent exception ou o valor vai retornar incorreto?

vlw

B

A resposta correta é: Não se sabe qual o valor do retorno.

Não vai atirar uma exceção por que a especificação do Java não fala nada sobre isso. Se quiser que aconteça uma exceção, você terá que implementá-la.

ViniGodoy

Sim, caso contrário, não há necessidade sequer de sincronizá-lo. As variáveis locais serão diferentes em cada thread, portanto, não se tratam da mesma região de memória, isto é, não há região crítica para se incomodar.

Agora, se você adota como prática usar métodos estáticos só pelo fato de “serem mais rápidos”, duvido muito que você não irá criar uma variável estática cedo ou tarde.

ViniGodoy
jmmenezes:
public static String converterDataString(Date cal, String formato) throws CoreException {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(formato);
			String dataStr = sdf.format(cal);
			return dataStr;
		} catch (Exception ex) {
			throw new CoreException("Erro em converterDataString.", ex);
		}
	}

Nesse caso não há problema, pois o método só usa variáveis locais. Cada thread inicializará seu próprio conjunto de variáveis desse tipo, portanto, não há memória sendo compartilhada.
O problema ocorre em um método assim:

public static final SimpleDateFormat FORMATO_PADRAO = new SimpleDateFormat("dd/MM/yyyy");

public static String converterDataString(Date cal) throws CoreException {
		try {
			String dataStr = FORMATO_PADRAO.format(cal);
			return dataStr;
		} catch (Exception ex) {
			throw new CoreException("Erro em converterDataString.", ex);
		}
	}

Se sincronizar esse método, você está criando um ponto onde todas as threads do sistema irão se enfileirar - não interessando que objeto estão percorrendo.

Por isso a alternativa de usar um threadLocal, que o entanglement falou. O threadLocal simplesmente cria uma cópia do FORMATO_PADRAO em cada thread. Assim, threads diferentes estarão percorrendo objetos diferentes.

Enfim, é ter que lembrar desse tipo de cuidado que significa "serem mais difíceis de serem usados em contexto multithread".

ViniGodoy

Esqueci de mais um problema, mas relacionado a variáveis estáticas:
Variáveis estáticas nunca saem de escopo. Portanto, o que referenciam só será coletado pelo garbage collector se essas variáveis forem explicitamente atribuídas a null.

Se você tiver como prática criar muitos métodos estáticos, cedo ou tarde usará variáveis desse tipo para gerenciar seus módulos… e aí, complicou a questão de threads e de coleta de lixo.

Não é à toa que variáveis estáticas estão entre as principais causas de memory leaks.

E

Hum… lembrei de mais um detalhinho chato de static + synchronized.

Digamos que você, como eu, tenha o costume de organizar seus métodos estáticos utilitários em uma única classe. Se você tivesse feito algo como

public class Util {
    protected Util() { }
    public synchronized static String formatarData () { ... }
    private static DateFormat formatoData = ...;
    public synchronized static String formatarHora () { ... }
    private static DateFormat formatoHora = ...;
}

vai constatar que a execução de formatarData() e a execução de formatarHora() estão sendo mutuamente excludentes, o que não é o efeito desejado porque elas deveriam ser independentes entre si (afinal de contas, synchronized deve proteger apenas o objeto que não é thread-safe, ou seja, formatoData ou formatoHora. É que

public synchronized static String formatarData() { ... }
    public synchronized static String formatarHora () { ... }

equivale, para fins de sincronização, a

public static String formatarData() { 
        synchronized (Util.class) { .... }
    }
    public static String formatarHora() { 
        synchronized (Util.class) { .... }
    }

ou seja, eles estão sincronizando no mesmo objeto, quando na verdade deveriam sincronizar em objetos diferentes (respectivamente, formatoData e formatoHora).

Até aprender todas essas sutilezas é melhor evitar o uso de synchronized, a menos que seja completamente inevitável.

J

ViniGodoy:
Esqueci de mais um problema, mas relacionado a variáveis estáticas:
Variáveis estáticas nunca saem de escopo. Portanto, o que referenciam só será coletado pelo garbage collector se essas variáveis forem explicitamente atribuídas a null.

Se você tiver como prática criar muitos métodos estáticos, cedo ou tarde usará variáveis desse tipo para gerenciar seus módulos… e aí, complicou a questão de threads e de coleta de lixo.

Não é à toa que variáveis estáticas estão entre as principais causas de memory leaks.

É o tipo de coisa que só se deve usar quando tem certeza o que esta fazendo… mas esse assunto é longo…

ViniGodoy

Isso me lembrou uma coisa, @Entanglement.

Alguns livros recomendam fazer assim:

public static String formatarHora() { synchronized (formatoHora) { .... } }

Até parece uma boa idéia, entretanto, descobri da pior maneira possível que essa não é uma boa prática.

Isso porque você tem que ter absoluta certeza que outras classes não farão a mesma coisa que você, em especial, a própria classe DateFormat. Como você não pode ler o conteúdo interno das classes (pois a OO insiste nessa história de encapsulamento), pode acabar com um deadlock em mãos, afinal, você não sabe em que contextos outras classes podem ter a mesma idéia que você.

O ideal MESMO seria criar sua própria lock.

Agora, tudo isso poderia ser evitado se tudo isso não rodasse num contexto estático, mas de um objeto. Nesse contexto, você pode simplesmente considerar a possibilidade de cada thread rodar com seu próprio objeto, sem ter que para isso recorrer a threadlocals e outras coisas sinistras do tipo.

sergiotaborda

jmmenezes:

Como sempre evitei métodos estáticos, fiquei na duvida se este código pode apresentar problema:

public static String converterDataString(Date cal, String formato) throws CoreException { try { SimpleDateFormat sdf = new SimpleDateFormat(formato); String dataStr = sdf.format(cal); return dataStr; } catch (Exception ex) { throw new CoreException("Erro em converterDataString.", ex); } }

Este é o código correto. Sem sincronismo ou threadlocal. Ok que temos que criar um objeto a cada execução, mas e daí ? como eu disse isso é grátis na jvm e aliás é o que fazemos quando usamos o operador + com strings, toda a hora um StringBulder será criado… Criar objetos não é problema.

Este erro especifico do uso do SimpleDateFormat realmente é chato e é preciso ter lido o javadoc com muita atenção ou ter passado problemas com isso. Eu nem sabia deste problema (porque uso o codigo como acima), mas um dia resolvi que poderia tornar o formatador estático em uma classe de utils da vida. Como eu descobrir que era furada? usando o firebugs. Esta ferramenta é muito boa para avisar de coisas que não são nada intuitivas. Portanto, aconselho a passar o firebug nos vossos codigos a fim de descobrir furadas como esta ( ou a usar o sonar que já inclui o firebugs e muitas outras ferramentas de qualidade)

J

sergiotaborda:
jmmenezes:

Como sempre evitei métodos estáticos, fiquei na duvida se este código pode apresentar problema:

public static String converterDataString(Date cal, String formato) throws CoreException { try { SimpleDateFormat sdf = new SimpleDateFormat(formato); String dataStr = sdf.format(cal); return dataStr; } catch (Exception ex) { throw new CoreException("Erro em converterDataString.", ex); } }

Este é o código correto. Sem sincronismo ou threadlocal. Ok que temos que criar um objeto a cada execução, mas e daí ? como eu disse isso é grátis na jvm e aliás é o que fazemos quando usamos o operador + com strings, toda a hora um StringBulder será criado… Criar objetos não é problema.

Este erro especifico do uso do SimpleDateFormat realmente é chato e é preciso ter lido o javadoc com muita atenção ou ter passado problemas com isso. Eu nem sabia deste problema (porque uso o codigo como acima), mas um dia resolvi que poderia tornar o formatador estático em uma classe de utils da vida. Como eu descobrir que era furada? usando o firebugs. Esta ferramenta é muito boa para avisar de coisas que não são nada intuitivas. Portanto, aconselho a passar o firebug nos vossos codigos a fim de descobrir furadas como esta ( ou a usar o sonar que já inclui o firebugs e muitas outras ferramentas de qualidade)

Foi o que falei a respeito do escopo (pelo menos aprendi assim) … rs rs rs
Mas achei que pudesse ter algo dentro do SimpleDateFormat que mesmo instânciando sempre o objeto pudesse dar problemas… por isso a duvida…

Estas ferramentas de validar código realmente ajudam a evitar alguns anti-patterns… só não acho correto seguir a risca tudo que elas recomendam (sempre há exceções onde sabemos o que estamos fazendo), mas eu também costumo usá-las bastante atualmente (um dia já cheguei a achar que elas só serviam para encher o saco, como muita gente pensa, mas isso muda :P)

E

sergiotaborda:

public static String converterDataString(Date cal, String formato) throws CoreException { try { SimpleDateFormat sdf = new SimpleDateFormat(formato); String dataStr = sdf.format(cal); return dataStr; } catch (Exception ex) { throw new CoreException("Erro em converterDataString.", ex); } }

Este é o código correto. Sem sincronismo ou threadlocal. Ok que temos que criar um objeto a cada execução, mas e daí ? como eu disse isso é grátis na jvm[/quote]
Grátis não é, o construtor de SimpleDateFormat não roda em tempo zero :slight_smile: Ele precisa de fazer um parse da string de formatação, e esse parse não é tao trivial assim. Alocar o objeto pode ser quase de graça, mas criá-lo pode ser custoso.

J

entanglement:
sergiotaborda:

public static String converterDataString(Date cal, String formato) throws CoreException { try { SimpleDateFormat sdf = new SimpleDateFormat(formato); String dataStr = sdf.format(cal); return dataStr; } catch (Exception ex) { throw new CoreException("Erro em converterDataString.", ex); } }

Este é o código correto. Sem sincronismo ou threadlocal. Ok que temos que criar um objeto a cada execução, mas e daí ? como eu disse isso é grátis na jvm


Grátis não é, o construtor de SimpleDateFormat não roda em tempo zero :slight_smile: Ele precisa de fazer um parse da string de formatação, e esse parse não é tao trivial assim. Alocar o objeto pode ser quase de graça, mas criá-lo pode ser custoso.

[/quote]

Acho que ai já vamos entrar em um cenário onde esse custo terá ou não impacto nos processos do sistema, que poderão levar a adotar uma solução totalmente diferente! :slight_smile:

ViniGodoy

Isso aconteceria se o objeto acessasse uma variável estática (não é o caso aqui).
Isso é chamado de classe “Thread-hostile”.

Ou seja, uma classe extremamente difícil de sincronizar. Veja que é algo extremamente sujeito a erros, já que ela não demonstraria ser hostil em sua interface pública (você só descobriria isso com muita analise, profiling e depuração… isso se descobrisse).

J

ViniGodoy:

Foi o que falei a respeito do escopo (pelo menos aprendi assim) … rs rs rs
Mas achei que pudesse ter algo dentro do SimpleDateFormat que mesmo instânciando sempre o objeto pudesse dar problemas… por isso a duvida…

Isso aconteceria se o objeto acessasse uma variável estática (não é o caso aqui).
Isso é chamado de classe “Thread-hostile”.

Ou seja, uma classe extremamente difícil de sincronizar. Veja que é algo extremamente sujeito a erros, já que ela não demonstraria ser hostil em sua interface pública (você só descobriria isso com muita analise, profiling e depuração… isso se descobrisse).


E Vini? Você conhece algum da api do java que tenha este problema e precisamos tomar este cuidado ??? ou se tiver isso pode ser considerado um bug ???

ViniGodoy

Não conheço. E se tiver é bug.

G

entanglement:
ViniGodoy:
Métodos estáticos são mais difíceis de usar em contextos de multiplas threads - o que pode ter um impacto significativamente ruim na performance;

Uma vez eu resolvi criar um método estático para formatar datas de acordo com um determinado padrão fixo de um SimpleDateFormat. O único problema é que o SimpleDateFormat não é thread-safe. (Eu não tinha lido as letras miúdas). Após bater a cabeça depois de alguns erros esporádicos muito estranhos, eu acabei descobrindo que:
a) Isso tinha sido registrado no Bug DataBase da Sun
b) e que a Sun (hoje Oracle) não ia resolver isso.

O método continuou estático, mas tive de usar um ThreadLocal para criar uma instância do SimpleDateFormat para cada thread. Isso foi muito chato de descobrir, e é um exemplo de que tipos de problemas podem ter métodos estáticos.

mas o problema não foi o metodo estático, e sim a instancia estatica.

G

entanglement:
Resolver resolve, mas eu não gosto de sincronização porque sincronização = serialização, e se você serializar uma operação lenta (formatação de datas) ela pode se tornar um gargalo no sistema.

Dentro da medida do possível, deve-se evitar a sincronização, a menos que isso seja inevitável e você não tenha realmente uma boa alternativa (no meu caso, uma ThreadLocal resolvia bem meu problema, porque transformava o problema de sincronizar uma operação lenta (formatar uma data) no problema de sincronizar uma operação que em média é rápida (escolher no HashMap embutido no ThreadLocal o objeto correspondente à thread corrente).

no java tem algo similar a threadvar?

G

Isso só vale se quando o método estático usa uma variável compartilhada (leia-se, externa ao método), não é Vini?

+1

G

entanglement:
Hum… lembrei de mais um detalhinho chato de static + synchronized.

Digamos que você, como eu, tenha o costume de organizar seus métodos estáticos utilitários em uma única classe. Se você tivesse feito algo como

public class Util {
    protected Util() { }
    public synchronized static String formatarData () { ... }
    private static DateFormat formatoData = ...;
    public synchronized static String formatarHora () { ... }
    private static DateFormat formatoHora = ...;
}

vai constatar que a execução de formatarData() e a execução de formatarHora() estão sendo mutuamente excludentes, o que não é o efeito desejado porque elas deveriam ser independentes entre si (afinal de contas, synchronized deve proteger apenas o objeto que não é thread-safe, ou seja, formatoData ou formatoHora. É que

public synchronized static String formatarData() { ... }
    public synchronized static String formatarHora () { ... }

equivale, para fins de sincronização, a

public static String formatarData() { 
        synchronized (Util.class) { .... }
    }
    public static String formatarHora() { 
        synchronized (Util.class) { .... }
    }

ou seja, eles estão sincronizando no mesmo objeto, quando na verdade deveriam sincronizar em objetos diferentes (respectivamente, formatoData e formatoHora).

Até aprender todas essas sutilezas é melhor evitar o uso de synchronized, a menos que seja completamente inevitável.

mas ai o problema foi do synchronized e não do static.

E

GilsonNunes:

no java tem algo similar a threadvar?

Java: ThreadLocal ( http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html )
C++ (Microsoft C++): __declspec (thread)
C++ (GCC) : __thread
C++ (Boost): boost::thread_specific_ptr
C#: [ThreadStatic]

Note que [ThreadStatic] é um atributo que se aplica, no C#, a variáveis estáticas. É que nesse caso ele usa o suporte que o Windows dá a esse tipo de armazenagem (“thread local storage”).
No caso do Java, uma variável declarada como ThreadLocal não precisa ser estática. O Java, entretanto, não usa esse suporte que o sistema operacional dá - ele usa uma coisa muito mais simples conceitualmente, que é um mapa Thread -> instância da variável.

G

GilsonNunes:
entanglement:
Resolver resolve, mas eu não gosto de sincronização porque sincronização = serialização, e se você serializar uma operação lenta (formatação de datas) ela pode se tornar um gargalo no sistema.

Dentro da medida do possível, deve-se evitar a sincronização, a menos que isso seja inevitável e você não tenha realmente uma boa alternativa (no meu caso, uma ThreadLocal resolvia bem meu problema, porque transformava o problema de sincronizar uma operação lenta (formatar uma data) no problema de sincronizar uma operação que em média é rápida (escolher no HashMap embutido no ThreadLocal o objeto correspondente à thread corrente).

no java tem algo similar a threadvar?

me parece q ja foi respondido.

se entedi bem é o threadLocal

E

É que normalmente uma coisa leva a outra. Se você for abusar muito do static, vai acabar vendo que para resolver alguns problemas vai precisar ou de um ThreadLocal ou de um synchronized, e por aí vai. Eu só mostrei que saber usar o synchronized não é tão trivial assim quanto parece.

G

entanglement:
GilsonNunes:

no java tem algo similar a threadvar?

Java: ThreadLocal ( http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html )
C++ (Microsoft C++): __declspec (thread)
C++ (GCC) : __thread
C++ (Boost): boost::thread_specific_ptr
C#: [ThreadStatic]

Note que [ThreadStatic] é um atributo que se aplica, no C#, a variáveis estáticas. É que nesse caso ele usa o suporte que o Windows dá a esse tipo de armazenagem (“thread local storage”).
No caso do Java, uma variável declarada como ThreadLocal não precisa ser estática. O Java, entretanto, não usa esse suporte que o sistema operacional dá - ele usa uma coisa muito mais simples conceitualmente, que é um mapa Thread -> instância da variável.

entanglement, mt obrigado pela resposta.

sou novato no mundo java. mas observando essa discursão sobre o sincronismo, não seria o caso de usar algo imutável?

G

e não é mesmo. vc ta certíssimo!

eu por exemplo fico “emulando” varias situações aki, pra ver na prática os efeitos desse no java, no intuito de entender melhor.
mas acompanhar essas discursões, aki no Guj, tem sido mt enriquecedor.
grato a tds.

E

Pois é.
Certas classes (como o SimpleDateFormat) não parecem ser imutáveis, à primeira vista? Eu achava isso até que tive problemas com ela (obviamente eu não havia lido o Javadoc e não tinha visto que ela não era “thread-safe”. )
É que você passa o formato no construtor (e você não pode mudar o formato depois, embora haja setters para mudar algumas outras coisas) e eu só usei, no caso em que houve problemas, para formatar alguma coisa, não para fazer um “parse” - nunca ia pensar que houvesse algum estado interno que fosse dar problemas se o código fosse chamado simultaneamente por duas ou mais threads.

ViniGodoy

Sim, Gilson, como já falamos no tópico os problemas são quando aparecem variáveis estáticas. Como eu já havia explicado, após o post do Bruno, se o método estático tiver só variáveis locais, nem mesmo sincronização será necessária.

Eu mesmo, na minha primeira afirmação, não falei que métodos estáticos fossem o problema per se, mas sim, que são mais difíceis de se gerenciar em multi-threading. E isso são, pois você terá que cuidar justamente para variáveis estáticas não aparecerem e terá que gerenciar com mais cuidado os locks que eles utilizarem. Ou, acaba enfileirando seu sistema inteiro.

Porém, o tema central do tópico é “utilizar métodos muitos estáticos por todo o programa”. Nesse caso, usar isso como política de desenvolvimento, com a intenção de obter performance, irá promover o aparecimento de variáveis desse tipo. E, consequentemente, estragar um possível paralelismo do sistema, com um resultado muito mais drástico à performance do que o custo de invocação tem.

E

Se alguém de vocês é um programador Linux/Unix, eu comparo a situação de botar statics no programa inteiro com a de criar um programa que só roda como o usuário “root”, só porque não entendeu como se lida com as permissões de uso dos arquivos e outros recursos.

Isso costuma indicar que o programador não entendeu alguma coisa e ficou com preguiça de correr atrás para entender como é que se fazem as coisas corretamente.

ViniGodoy

entanglement:
Se alguém de vocês é um programador Linux/Unix, eu comparo a situação de botar statics no programa inteiro com a de criar um programa que só roda como o usuário “root”, só porque não entendeu como se lida com as permissões de uso dos arquivos e outros recursos.

Isso costuma indicar que o programador não entendeu alguma coisa e ficou com preguiça de correr atrás para entender como é que se fazem as coisas corretamente.

Concordo.

Existe um argumento, muito usado nas discussões com programadores C++, de que “ah, mas se o erro é assim, é porque a culpa do programador”. Eles geralmente usam isso quando demonstramos alguma coisa que a linguagem é capciosa e induz ao erro. Como por exemplo, nas discussões sobre ainda usar ponteiros versus usar linguagens gerenciadas.

É um argumento que detesto porque, no firgir dos ovos, todo e qualquer erro de software é um erro de programador. Com um argumento desses, você pode até dizer que assembly é fácil, e que se houver algum problema, é erro do programador.

A diferença é que bons programadores criam designs de software que promovem a ausência de erros:

  • Criam abstrações que os impeçam de mexer nas variáveis em contextos que não deveriam;
  • Criam testes unitários e verificam parâmetros de entrada;
  • Fazem o compilador trabalhar por eles em verificações;

Programar em modo root ou programar só usando statics é possível, mas é o que um programador ruim faria. Afinal, é pedir para ter problemas, sem um argumento técnico suficientemente convicente para isso.

G

ViniGodoy:
Sim, Gilson, como já falamos no tópico os problemas são quando aparecem variáveis estáticas. Como eu já havia explicado, após o post do Bruno, se o método estático tiver só variáveis locais, nem mesmo sincronização será necessária.

Eu mesmo, na minha primeira afirmação, não falei que métodos estáticos fossem o problema per se, mas sim, que são mais difíceis de se gerenciar em multi-threading. E isso são, pois você terá que cuidar justamente para variáveis estáticas não aparecerem e terá que gerenciar com mais cuidado os locks que eles utilizarem. Ou, acaba enfileirando seu sistema inteiro.

Porém, o tema central do tópico é “utilizar métodos muitos estáticos por todo o programa”. Nesse caso, usar isso como política de desenvolvimento, com a intenção de obter performance, irá promover o aparecimento de variáveis desse tipo. E, consequentemente, estragar um possível paralelismo do sistema, com um resultado muito mais drástico à performance do que o custo de invocação tem.

obrigado vini, entendi sua colocação.

tgcmv

Isso só vale se quando o método estático usa uma variável compartilhada (leia-se, externa ao método), não é Vini?

Acredito que sim, devido ao escopo… ou estou errado ???
Como sempre evitei métodos estáticos, fiquei na duvida se este código pode apresentar problema:

public static String converterDataString(Date cal, String formato) throws CoreException { try { SimpleDateFormat sdf = new SimpleDateFormat(formato); String dataStr = sdf.format(cal); return dataStr; } catch (Exception ex) { throw new CoreException("Erro em converterDataString.", ex); } }

O que jmmenezes falou faz sentido
Gostaria de saber quanto a esse comentário

ViniGodoy:
a) Métodos estáticos são mais difíceis de usar em contextos de multiplas threads - o que pode ter um impacto significativamente ruim na performance;
http://www.guj.com.br/java/280370-resolvido-qual-tem-a-melhor-performance-estatico-ou-dinamico

Gostaria de saber um pouco mais sobre isso, alguem recomenda algum artigo? Vale a pena eu alterar um sistema antigo com um método static similar ao citado aqui?
OBS.: O método static em questão é usado em diversas servlet, que por sua vez possuem diversas threads.

A questão final é o trabalho compensa? Todos os outros comentários me levaram a entender que não. O problema é essa frase:

ViniGodoy:
a) Métodos estáticos são mais difíceis de usar em contextos de multiplas threads - o que pode ter um impacto significativamente ruim na performance;

E

Não mexa no que está funcionando

jacobis

kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
Dizer antigo mas funcional mesmo… Veja bem ach que o que Vini quiz dizer foi que quando você usa muitos métodos státicos tem-se um grande problema em realação ao acesso. E Threads trabalha em cima disso, claro. Então se um método estático só pode ser visto por outro estático, imagine se você quer atualizar através de um não-estático, imagina isso em diversas Threads, como encontrar o erro???

Porisso torna o código menos legível com toda certeza!

G

o q vc quiz dizer com isso?
creio q o q se explicitou, não é, na verdade o q quiz mesmo dizer.

Criado 7 de agosto de 2012
Ultima resposta 20 de ago. de 2012
Respostas 45
Participantes 10