Tenho o seguinte cenário:
Inicio uma thread que de tempos em tempos realiza um processo de sincronização de horário, nesta thread utilizo um .sleep() de 5 segundos para não usar todo o recurso da máquina. A fim de validar este procedimento, alterei o horário da máquina para verificar se a sincronização era realizada. Ao alterar o relógio para o futuro, o processo funciona, porém, ao atrasar o relógio a execução para no Thread.Sleep(5000). Isso só está ocorrendo no SO Linux, no windows não consegui reproduzir este problema, porém preciso que funcione no linux.
Alguém saberia se tem algo que possa resolver este problema? porque o java responde desta forma?
Lembrando que o processo que uso para sincronizar o horário não chega a ser executado, então não tem relação ao problema. Mesmo porque qualquer Thead.Sleep() fica congelado.
Me parece que isso já foi resolvido. Ao menos é o que diz na página do bug.
Fiz um teste aqui:
importjava.util.Date;publicclassSleep{publicstaticvoidmain(String[]args)throwsInterruptedException{System.out.println("Vou dormir por 10 segundos...");System.out.println(newDate());Thread.sleep(10000);System.out.println("OK!");System.out.println(newDate());}}
$java-version
javaversion"1.6.0_20"
OpenJDKRuntimeEnvironment(IcedTea61.9.2)(6b20-1.9.2-0ubuntu1)
OpenJDKClientVM(build19.0-b09,mixedmode,sharing)
$uname-a
Linux2.6.37-020637rc2-generic#201011160905 SMP Tue Nov 16 10:15:47 UTC 2010 i686 GNU/Linux
Funcionou tanto sem alterar a hora, quanto alterando para o futuro ou para o passado (só não foi tão preciso assim o tempo que a Thread dormiu…).
E
entanglement
Ainda tem gente que roda Java 5.0, onde esse problema não foi resolvido
V
vctlzac
Nova descoberta. Testei em Ubuntu e o thread.sleep() não parou. Mas no fedora o problema acontece, e tenho a necessidade que funcione nele. Será que o marcobiscaro2112 ou alguém conseguiria testar no fedora ?
Sobre a página do bug , nela está citando CLOCK_MONOTONIC, onde pelo que entendi através dele o calculo de hora não sofre alterações. Pelo java, conforme pesquisei é acessado via System.NanoTime(), porém não consegui vincular essa funcionalidade para Thread.Sleep().
Puxa, será que tem alguma diferença entre o IcedTea 1.8.2 e o 1.9.2 que incluiu (ou não) essa alteração?
De qualquer maneira, em um dos comentários nesse bug da Sun, indicou-se que talvez você possa trocar por
synchronized(this) {
wait(1000);
}
V
vctlzac
entanglement:
Puxa, será que tem alguma diferença entre o IcedTea 1.8.2 e o 1.9.2 que incluiu (ou não) essa alteração?
De qualquer maneira, em um dos comentários nesse bug da Sun, indicou-se que talvez você possa trocar por
synchronized(this) {
wait(1000);
}
Descobri que este problema ocorre no Fedora 64 bits. Testei em um fedora 32 bits e não parou no sleep.
entanglement , também observei esse comentário.
Vou testar e já posto.
Valeu.
V
vctlzac
Com wait ocorre o mesmo problema.
Talvez o usuário que postou sobre o wait não tenha percebido um detalhe. Se o relógio for atrasado e neste momento a thread não está parada no wait, o problema não ocorre, ou seja , quando ele parar no wait, vai esperar os milissegundos do parametro e sair normal, porém, se o atraso do relógio for gerado no momento em que a execução estiver parada no wait, ai sim o problema ocorre. Após perceber isso também verifiquei no caso do Thread.Sleep() e percebi que essas condições também acontecem para ele.
Agradeço qualquer nova ajuda.
Obrigado.
E
entanglement
Puxa - será que tal bug só foi corrigido no Linux 32 bits? É que o Ubuntu do Marco Biscaro é em 32 bits.
(A propósito, não tenho aqui uma máquina com Linux em que eu tenha acesso administrativo para testar. Não consigo lhe afirmar nada - embora seja perfeitamente possível baixar os fontes do OpenJDK para ver se o pessoal da saudosa Sun corrigiu mesmo isso em 64 bits também.)
V
vctlzac
entanglement:
Puxa - será que tal bug só foi corrigido no Linux 32 bits? É que o Ubuntu do Marco Biscaro é em 32 bits.
(A propósito, não tenho aqui uma máquina com Linux em que eu tenha acesso administrativo para testar. Não consigo lhe afirmar nada - embora seja perfeitamente possível baixar os fontes do OpenJDK para ver se o pessoal da saudosa Sun corrigiu mesmo isso em 64 bits também.)
Entendo.
É , olhar o jdk é uma possibilidade, embora essa resposta não iria ajudar muito pois o fato é que não está funcionando.
M
marcobiscaro2112
Também não tenho uma máquina 64 bits para testar. Mas olhando o código fonte do JDK 6, não houve mudança na implementação do sleep do build 18 para o build 20.
Esse método e o método os::sleep (linha 2790) estão idênticos entre o b18 e o b20.
Não encontrei nenhum indício que há distinção de métodos entre uma JVM 32 bits e uma 64 bits.
Será que não procurei direito ou o problema está em outro lugar?
M
marcobiscaro2112
Aliás, no método os::sleep, caso o tempo do sistema seja mudado para o passado, ele simplesmente não altera o tempo que ainda falta para dormir:
for(;;){if(os::is_interrupted(thread,true)){returnOS_INTRPT;}jlongnewtime=javaTimeNanos();if(newtime-prevtime<0){//timemovingbackwards,shouldonlyhappenifnomonotonicclock//notaguarantee()becauseJVMshouldnotabortonkernel/glibcbugsassert(!Linux::supports_monotonic_clock(),"time moving backwards");//NÃOALTERAOVALORDEmillis}else{millis-=(newtime-prevtime)/NANOSECS_PER_MILLISECS;}if(millis<=0){//NOCASODEVOLTAROTEMPO,ISSONÃOOCORRERÁreturnOS_OK;}prevtime=newtime;{assert(thread->is_Java_thread(),"sanitycheck");JavaThread*jt=(JavaThread*)thread;ThreadBlockInVMtbivm(jt);OSThreadWaitStateosts(jt->osthread(),false/* not Object.wait() */);jt->set_suspend_equivalent();//clearedbyhandle_special_suspend_equivalent_condition()or//java_suspend_self()viacheck_and_wait_while_suspended()slp->park(millis);//wereweexternallysuspendedwhilewewerewaiting?jt->check_and_wait_while_suspended();}}
Isso significa que o mesmo problema reportado ainda ocorre caso o kernel não suporte o relógio de hardware (ou caso a JVM, por algum motivo, não reconheça o suporte). Seria esse o caso?
V
vctlzac
marcobiscaro2112:
Também não tenho uma máquina 64 bits para testar. Mas olhando o código fonte do JDK 6, não houve mudança na implementação do sleep do build 18 para o build 20.
Esse método e o método os::sleep (linha 2790) estão idênticos entre o b18 e o b20.
Não encontrei nenhum indício que há distinção de métodos entre uma JVM 32 bits e uma 64 bits.
Será que não procurei direito ou o problema está em outro lugar?
Interessante.
Eu também tenho dúvidas com relação aos métodos.
Talvez uma saída fosse verificar se o relógio monotônico está disponível na máquina, alguém sabe como se faz isso ?
Talvez ele não desse mais problema se eu conseguisse ativar isso.
M
marcobiscaro2112
vctlzac:
Talvez uma saída fosse verificar se o relógio monotônico está disponível na máquina, alguém sabe como se faz isso ?
Talvez ele não desse mais problema se eu conseguisse ativar isso.
Bem, extraindo a parte que verifica o suporte ao relógio via hardware, chegamos a isso:
# include <stdio.h># include <dlfcn.h># include <time.h>#ifndef CLOCK_MONOTONIC#define CLOCK_MONOTONIC (1)#endifintmain(){void*handle=dlopen("librt.so.1",RTLD_LAZY);if(handle==NULL){handle=dlopen("librt.so",RTLD_LAZY);}if(handle){int(*clock_getres_func)(clockid_t,structtimespec*)=(int(*)(clockid_t,structtimespec*))dlsym(handle,"clock_getres");int(*clock_gettime_func)(clockid_t,structtimespec*)=(int(*)(clockid_t,structtimespec*))dlsym(handle,"clock_gettime");if(clock_getres_func&&clock_gettime_func){structtimespecres;structtimespectp;if(clock_getres_func(CLOCK_MONOTONIC,&res)==0&&clock_gettime_func(CLOCK_MONOTONIC,&tp)==0){printf("OK!\n");}else{printf("Sem suporte...\n");}}dlclose(handle);}}
Você pode compilar e executar isso nas duas máquinas (lembrando que é preciso compilar uma vez em cada máquina - 32 e 64 bits):
Se NÃO imprimir um valor de 200112 então você tem um problema.
EDIT- Eu acabei escrevendo a palavra errada, sorry. É se NÂO imprimir.
Ao executar este último código, o retorno foi “200809”.
Sabe dizer o que representa ?
M
marcobiscaro2112
vctlzac:
Ao executar este último código, o retorno foi “200809”.
Sabe dizer o que representa ?
O mesmo aqui. Você testou no Fedora 64 bits?
V
vctlzac
marcobiscaro2112:
vctlzac:
Ao executar este último código, o retorno foi “200809”.
Sabe dizer o que representa ?
O mesmo aqui. Você testou no Fedora 64 bits?
Sim , este valor 200809 foi gerado no fedora 64 bits.
Só pra eu entender, valores diferentes de 200112 representam problema ?
M
marcobiscaro2112
vctlzac:
marcobiscaro2112:
vctlzac:
Ao executar este último código, o retorno foi “200809”.
Sabe dizer o que representa ?
O mesmo aqui. Você testou no Fedora 64 bits?
Sim , este valor 200809 foi gerado no fedora 64 bits.
Só pra eu entender, valores diferentes de 200112 representam problema ?
Se representarem, estou com um problema. Mas quando voltei o relógio do sistema a Thread retomou de forma correta. Você rodou o código que postei?
V
vctlzac
marcobiscaro2112:
vctlzac:
marcobiscaro2112:
vctlzac:
Ao executar este último código, o retorno foi “200809”.
Sabe dizer o que representa ?
O mesmo aqui. Você testou no Fedora 64 bits?
Sim , este valor 200809 foi gerado no fedora 64 bits.
Só pra eu entender, valores diferentes de 200112 representam problema ?
Se representarem, estou com um problema. Mas quando voltei o relógio do sistema a Thread retomou de forma correta. Você rodou o código que postei?
Você diz este código ?
# include <stdio.h># include <dlfcn.h># include <time.h>#ifndef CLOCK_MONOTONIC#define CLOCK_MONOTONIC (1)#endifintmain(){void*handle=dlopen("librt.so.1",RTLD_LAZY);if(handle==NULL){handle=dlopen("librt.so",RTLD_LAZY);}if(handle){int(*clock_getres_func)(clockid_t,structtimespec*)=(int(*)(clockid_t,structtimespec*))dlsym(handle,"clock_getres");int(*clock_gettime_func)(clockid_t,structtimespec*)=(int(*)(clockid_t,structtimespec*))dlsym(handle,"clock_gettime");if(clock_getres_func&&clock_gettime_func){structtimespecres;structtimespectp;if(clock_getres_func(CLOCK_MONOTONIC,&res)==0&&clock_gettime_func(CLOCK_MONOTONIC,&tp)==0){printf("OK!\n");}else{printf("Sem suporte...\n");}}dlclose(handle);}}
Este não executei … achei que se rodasse o outro poderia descartar este.
O que esse código faz ?
M
marcobiscaro2112
vctlzac:
Você diz este código ?
Este não executei … achei que se rodasse o outro poderia descartar este.
O que esse código faz ?
Esse mesmo. Acho interessante executá-lo também pois é uma pequena adaptação (na verdade, quase uma cópia) de como a JVM faz essa verificação (se há ou não suporte ao relógio monotônico).
V
vctlzac
marcobiscaro2112:
vctlzac:
Você diz este código ?
Este não executei … achei que se rodasse o outro poderia descartar este.
O que esse código faz ?
Esse mesmo. Acho interessante executá-lo também pois é uma pequena adaptação (na verdade, quase uma cópia) de como a JVM faz essa verificação (se há ou não suporte ao relógio monotônico).
# include <stdio.h># include <dlfcn.h># include <time.h>#ifndef CLOCK_MONOTONIC#define CLOCK_MONOTONIC (1)#endifintmain(){void*handle=dlopen("librt.so.1",RTLD_LAZY);if(handle==NULL){handle=dlopen("librt.so",RTLD_LAZY);}if(handle){int(*clock_getres_func)(clockid_t,structtimespec*)=(int(*)(clockid_t,structtimespec*))dlsym(handle,"clock_getres");int(*clock_gettime_func)(clockid_t,structtimespec*)=(int(*)(clockid_t,structtimespec*))dlsym(handle,"clock_gettime");if(clock_getres_func&&clock_gettime_func){structtimespecres;structtimespectp;if(clock_getres_func(CLOCK_MONOTONIC,&res)==0&&clock_gettime_func(CLOCK_MONOTONIC,&tp)==0){printf("OK!\n");}else{printf("Sem suporte...\n");}}dlclose(handle);}}
Desculpe, o relógio monotônico só não é suportado no Linux se esse sysconf(_SC_MONOTONIC_CLOCK) retornar -1.
Então … o que será que está ocorrendo? Muito misterioso
M
marcobiscaro2112
entanglement:
Desculpe, o relógio monotônico só não é suportado no Linux se esse sysconf(_SC_MONOTONIC_CLOCK) retornar -1.
Então … o que será que está ocorrendo? Muito misterioso
Muito mesmo… Mesmo resultado para ambos os testes. Em um funciona, em outro não. Será que Sherlock Holmes manja de C++ e de Linux para ajudar a resolver este caso?
V
vctlzac
marcobiscaro2112:
entanglement:
Desculpe, o relógio monotônico só não é suportado no Linux se esse sysconf(_SC_MONOTONIC_CLOCK) retornar -1.
Então … o que será que está ocorrendo? Muito misterioso
Muito mesmo… Mesmo resultado para ambos os testes. Em um funciona, em outro não. Será que Sherlock Holmes manja de C++ e de Linux para ajudar a resolver este caso? :)
Realmente, inexplicável. Talvez chuck norris 8) .
Bom, vo tentar postar isso no forum da sun, sei la, as vezes os cara dão uma luz.
De qualquer forma agradeço a ajuda de todos, e qualquer nova é bem-vinda.