Conforme documentado na publicação do blog Cuidado com System.nanoTime () em Java , em sistemas x86, o System.nanoTime () do Java retorna o valor do tempo usando um contador específico da CPU . Agora considere o seguinte caso que eu uso para medir o tempo de uma chamada:
long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
Agora, em um sistema com vários núcleos, pode ser que, após medir o tempo1, o encadeamento seja agendado para um processador diferente cujo contador seja menor que o da CPU anterior. Assim, poderíamos obter um valor no tempo2 que é menor que o tempo1. Assim, obteríamos um valor negativo em timeSpent.
Considerando esse caso, não é o System.nanotime que é praticamente inútil por enquanto?
Eu sei que mudar a hora do sistema não afeta o nanotime. Esse não é o problema que descrevi acima. O problema é que cada CPU mantém um contador diferente desde que foi ligado. Esse contador pode ser menor na segunda CPU em comparação com a primeira CPU. Como o encadeamento pode ser agendado pelo sistema operacional para a segunda CPU após obter o time1, o valor de timeSpent pode estar incorreto e até negativo.
Respostas:
Esta resposta foi escrita em 2011 do ponto de vista do que o Sun JDK da época em execução nos sistemas operacionais da época realmente fazia. Isso foi há muito tempo atrás! A resposta de leventov oferece uma perspectiva mais atualizada.
Esse post está errado e
nanoTime
é seguro. Há um comentário na postagem com um link de David Holmes , um cara em tempo real e simultâneo da Sun. Diz:Portanto, no Windows, esse era um problema até o WinXP SP2, mas não é agora.
Não consigo encontrar uma parte II (ou mais) que fala sobre outras plataformas, mas esse artigo inclui uma observação de que o Linux encontrou e resolveu o mesmo problema da mesma maneira, com um link para a FAQ do clock_gettime (CLOCK_REALTIME) , que diz:
Portanto, se o link de Holmes puder ser lido como implicando que
nanoTime
chamadasclock_gettime(CLOCK_REALTIME)
, é seguro a partir do kernel 2.6.18 no x86 e sempre no PowerPC (porque a IBM e a Motorola, ao contrário da Intel, sabem como projetar microprocessadores).Infelizmente, não há menção a SPARC ou Solaris. E, é claro, não temos idéia do que as JVMs da IBM fazem. Mas as JVMs da Sun no Windows e Linux modernos acertam isso.
EDIT: Esta resposta é baseada nas fontes que cita. Mas ainda me preocupo que isso possa estar completamente errado. Algumas informações mais atualizadas seriam realmente valiosas. Acabei de encontrar um link para um artigo mais recente de quatro anos sobre os relógios do Linux que poderia ser útil.
fonte
void foo() { Thread.sleep(40); }
eu tenho um tempo negativo (-380 ms!) Usando um únicoAthlon 64 X2 4200+
processadorPesquisei um pouco e descobri que, se alguém está sendo pedante, sim, pode ser considerado inútil ... em situações particulares ... depende de quão sensível ao tempo são suas exigências ...
Confira esta citação no site Java Sun:
Java também tem uma ressalva para o método nanoTime () :
Parece que a única conclusão que pode ser tirada é que nanoTime () não pode ser considerado um valor preciso. Dessa forma, se você não precisar medir tempos com apenas nano segundos de distância, esse método será bom o suficiente, mesmo que o valor retornado resultante seja negativo. No entanto, se você estiver precisando de maior precisão, eles parecerão recomendar o uso do JAVA RTS.
Portanto, para responder à sua pergunta ... o nanoTime () não é inútil ... não é o método mais prudente a ser usado em todas as situações.
fonte
-100
,-99
,-98
(Valores obviamente muito maiores na prática). Eles estão indo na direção correta (aumentando), então não há problema aqui.Não há necessidade de debater, basta usar a fonte. Aqui, o SE 6 para Linux, tire suas próprias conclusões:
fonte
Desde o Java 7,
System.nanoTime()
é garantido que seja seguro pela especificação JDK.System.nanoTime()
O Javadoc deixa claro que todas as invocações observadas em uma JVM (ou seja, em todos os threads) são monotônicas:A implementação da JVM / JDK é responsável por resolver as inconsistências que podem ser observadas quando os utilitários do SO subjacente são chamados (por exemplo, os mencionados na resposta de Tom Anderson ).
A maioria das outras respostas antigas para essa pergunta (escritas em 2009–2012) expressa FUD que provavelmente era relevante para Java 5 ou Java 6, mas não é mais relevante para versões modernas de Java.
Vale ressaltar, no entanto, que, apesar da segurança
nanoTime()
das garantias do JDK , houve vários bugs no OpenJDK, impedindo essa garantia em determinadas plataformas ou sob certas circunstâncias (por exemplo, JDK-8040140 , JDK-8184271 ). Não há bugs abertos (conhecidos) no OpenJDK wrtnanoTime()
, mas a descoberta de um novo bug ou uma regressão em uma versão mais recente do OpenJDK não deve chocar ninguém.Com isso em mente, o código usado
nanoTime()
para bloqueio cronometrado, espera em intervalos, tempos limite, etc. deve preferencialmente tratar diferenças de tempo negativas (tempos limite) como zeros, em vez de lançar exceções. Esta prática é também preferível porque é consistente com o comportamento de todos os métodos de espera temporizada em todas as classes emjava.util.concurrent.*
, por exemploSemaphore.tryAcquire()
,Lock.tryLock()
,BlockingQueue.poll()
, etc.No entanto,
nanoTime()
ainda deve ser preferido para a implementação de bloqueio cronometrado, intervalo de espera, tempo limite, etc.,currentTimeMillis()
porque este último está sujeito ao fenômeno "tempo atrasado" (por exemplo, devido à correção da hora do servidor), oucurrentTimeMillis()
seja, não é adequado para medir intervalos de tempo em absoluto. Veja esta resposta para mais informações.Em vez de usar
nanoTime()
diretamente para medições de tempo de execução de código, estruturas e perfis de benchmarking especializados devem ser usados preferencialmente, por exemplo, JMH e async-profiler no modo de criação de perfil de relógio de parede .fonte
Isenção de responsabilidade: eu sou o desenvolvedor desta biblioteca
Você pode gostar disso melhor:
http://juliusdavies.ca/nanotime/
Mas ele copia um arquivo DLL ou Unix .so (objeto compartilhado) no diretório inicial do usuário atual para que possa chamar JNI.
Algumas informações básicas estão no meu site em:
http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html
fonte
O Linux corrige discrepâncias entre CPUs, mas o Windows não. Eu sugiro que você suponha que System.nanoTime () é preciso apenas para cerca de 1 micro-segundo. Uma maneira simples de obter um tempo mais longo é chamar foo () 1000 ou mais vezes e dividir o tempo por 1000.
fonte
Absolutamente não é inútil. Os aficionados de tempo apontam corretamente o problema de vários núcleos, mas em aplicativos de palavras reais ele costuma ser radicalmente melhor que o currentTimeMillis ().
Ao calcular as posições gráficas no quadro, o nanoTime () leva a MUITO movimento mais suave no meu programa.
E eu só testei em máquinas com vários núcleos.
fonte
Vi um tempo decorrido negativo relatado usando System.nanoTime (). Para ser claro, o código em questão é:
e a variável 'elapsedNanos' teve um valor negativo. (Tenho certeza de que a chamada intermediária também levou menos de 293 anos, que é o ponto de sobrecarga para nanos armazenados em longos :)
Isso ocorreu usando um IBM v1.5 JRE 64bit no hardware IBM P690 (multi-core) executando o AIX. Eu só vi esse erro ocorrer uma vez, então parece extremamente raro. Não sei a causa - é um problema específico de hardware, um defeito da JVM - não sei. Também não sei as implicações para a precisão do nanoTime () em geral.
Para responder à pergunta original, não acho que o nanoTime seja inútil - ele fornece um tempo abaixo de milissegundos, mas há um risco real (não apenas teórico) de ser impreciso, o que você precisa levar em consideração.
fonte
Isso não parece ser um problema em um Core 2 Duo executando o Windows XP e o JRE 1.5.0_06.
Em um teste com três threads, não vejo System.nanoTime () retrocedendo. Os processadores estão ocupados e os threads entram em suspensão ocasionalmente para provocar a movimentação de threads.
[EDIT] Eu acho que isso acontece apenas em processadores fisicamente separados, ou seja, que os contadores são sincronizados para vários núcleos no mesmo dado.
fonte
Não, não é ... Depende apenas da sua CPU, verifique o temporizador de eventos de alta precisão para saber como / por que as coisas são tratadas de maneira diferente de acordo com a CPU.
Basicamente, leia a fonte do seu Java e verifique o que sua versão faz com a função, e se ela funcionar na CPU, você a executará.
A IBM ainda sugere que você o use para comparações de desempenho (uma publicação de 2008, mas atualizada).
fonte
Estou ligando ao que é essencialmente a mesma discussão em que Peter Lawrey está fornecendo uma boa resposta. Por que recebo um tempo decorrido negativo usando System.nanoTime ()?
Muitas pessoas mencionaram que no Java System.nanoTime () poderia retornar um tempo negativo. Peço desculpas por repetir o que outras pessoas já disseram.
Seria legal se System.nanoTime () retornasse coreID onde foi executado.
fonte
Java é multiplataforma e nanoTime depende da plataforma. Se você usa Java - quando não usa o nanoTime. Encontrei erros reais em diferentes implementações de jvm com esta função.
fonte
A documentação do Java 5 também recomenda o uso desse método para a mesma finalidade.
Doc da API do Java 5
fonte
Além disso,
System.currentTimeMillies()
muda quando você altera o relógio do sistema, enquantoSystem.nanoTime()
não muda , portanto, o último é mais seguro para medir durações.fonte
nanoTime
é extremamente inseguro para o tempo. Eu tentei nos meus algoritmos básicos de teste de primalidade e deu respostas que estavam literalmente com um segundo de diferença para a mesma entrada. Não use esse método ridículo. Preciso de algo que seja mais preciso e preciso do que ganhar tempo, mas não tão ruim quantonanoTime
.fonte