Bom pessoal gostaria de saber por que ocorre o seguinte erro
tenho a seguinte classe
public class ThreadStart {
public static void main(String[] args){
CreateExecutors ce = new CreateExecutors();
ExecutorService es = Executors.newFixedThreadPool(3);
while (true) {
try {
for (int i = 0; i < 2; i++) {
es.execute(ce.getExecutor());
}
} catch (Exception e) {
System.exit(1);
}
}
}
}
e a outra:
public class CreateExecutors {
private static Run exists = null;
public Run getExecutor(){
if(exists != null){
return exists;
}
exists = new Run();
return exists;
}
class Run implements Runnable{
DateFormat ft = SimpleDateFormat.getInstance();
public void run() {
((SimpleDateFormat)ft).applyPattern("HH:mm");
try {
ft.parse("00:01");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Ao rodar o código aparece vários erros, um deles é esse
java.lang.NumberFormatException: For input string: ""
Sei que concerteza é problema de sincronização e a solução seria abrir um dateFormat para cada thread mas eu quero entender qual é o erro que acontece, tentei debugar e entender. caso alguém ja saiba ficaria muito grato.
quero saber se é race condition,starvation,livelocks enfim. os mais sêniors vão saber explicar algo desse tipo.
Coloque seus códigos entre as tagd code.
NumberFormatException não é problema de sincronização. Em algum momento seu código tenta converter uma String ("", " ", ou algo como “bcd”) para número. Formate seu código e mais gente vai se animar a te ajudar.
Então J-Chist, sei que NumberFormatException não é um problema de sincronização, mas observe que esse código roda em threads, mas eu acho que ja achei o problema, dentro das classes do java, Date e outras usam variáveis que são escritas. provavelmente race codition.
O problema é que uma thread pode chamar o getInstance() e logo em seguida outra pode chamar o ft.parse(“00:01”);
Aí, nesse caso, o formato ainda não estará definido.
Sem falar que não sabemos exatamente o que os métodos fazem, então pode haver condições de corrida em seu interior.
A melhor solução é mesmo a que você falou, criar um DateFormatter por thread. Outra solução possível seria criar um Runnable por thread (é equivalente a anterior, mas é mais comum fazer assim e evita ter que usar o ThreadLocal). Outra possibilidade seria usar uma classe de formatação de datas imutável.
E a última solução seria sincronizar todo o método, impedindo que duas threads o chamem ao mesmo tempo. É pior pq vc serializa threads, o que vai contra o propósito de ter threads em primeiro lugar.
A J-Christ provavelmente não leu seu código porque não estava formatado. Use as tags code se quiser formata-lo. Se ainda não conhece esse recurso, dá uma lida aqui: http://www.guj.com.br/posts/list/50115.java
Ok vini obrigadão.
O problema não é apenas race condition?
O primeiro caso que você mencionou pode realmente acontecer?
Observe que a classe Run em sua instância, por definição possui uma instância de DateFormat e dentro do método run aplica-se um formato para a data.
mesmo assim tem como acontecer o primeiro caso? não consegui imaginar.
Aí depende do que o método getInstance() faça. Se ele ferrar com o formato, aí pode acontecer sim. Note que a documentação do método especifica o tipo de formato que o getInstance() retorna. E, tipicamente, métodos getInstance() retornam sempre a mesma instância, que estará sendo compartilhada pelas três threads.
Então, o que pode ocorrer? A sua primeira thread entra no run(), roda o comando getInstance(), roda o format, e então perde o processador (pela preempção normal).
A segunda thread, apenas entra no método e roda o getInstance(), que reseta o formato da data para o default. Por algum motivo exotérico, o SO decide alternar novamente para a primeira thread. Ao rodar o comando format, o objeto agora está com o formato default…
Lembre-se, só existem condições de corrida em objetos compartilhados. Quando você cria um DateFormatter para cada thread isso não ocorre mais. Cada thread tem acesso ao seu próprio espaço de memória, e não há mais condição de corrida.
hehe concordo com você, mas isso se o getinstance tivesse dentro do run. o que não é o caso certo?
você tem razão, mas quase certeza que o problema não é por causa do getinstance e sim internamente ao objeto date, o format alterna a forma que ele vai formatar a data, não olhei direito a api, até por que ja resolvi o problema, mas pelo o que eu percebi quando ele roda, internamente o format tem uma árvore de decisão desses formatos,em algum momento, nessas decisões uma thread está em outra classe tentando formatar um determinado tipo e a outra thread resolve rodar(por decisão do escalonador correto?) vai para o ínicio da árvore é onde ele se perde e acaba gerando o problema.
bom…
essa discusão é básica hehe mas valeu mesmo ai pelos conhecimentos.
Sim, isso seria para o caso do getInstance() estar dentro do Run.
Ou para o caso desse Runnable ser instanciado mais de uma vez, o que também não ocorre aqui.
Aproveitando, note o problemaço que é ter um método estático num contexto multi-threaded. Não estou mais falando desse caso.
Enquando uma thread acessa feliz e contente esse getInstance() num trecho sincronizado, outra pode estar acessando esse também num trecho sincronizado, com um monitor diferente. Como os trechos de código podem ser completamente distintos, você terá um problema de condição de corrida nas mãos dificílimo de resolver. Via de regra, quando você for usar multi-threads, fuja de coisas sincronizadas como o diabo foge da cruz.
Os objetos estáticos também podem fazer com que outros objetos se tornem “thread-hostile”. Ou seja, nem que você garanta completamente a execução de objetos thread hostile em trechos sincronizados, eles não serão thread-safe. Afinal, tem aquele estático compartilhado avacalhando com tudo.