Cronometro milissegundos que funcione

Olá pessoal

Bom, antes de mais nd, quero dizer que ja procurei aqui no guj, em outros foruns de discussao e no google, inclusive achei varios exemplos, mas nenhum resolveu a ultima parte do meu cronometro, que é os milissegundos, e que eu quero fazer um cronometro que mostre os minutos, segundos e os milissegundos, ou seja, de 0 a 999 antes de incrementar mais um nos segundos, como o cronometro de um relogio de pulso mesmo…

Bom abaixo segue um link de um post daqui do guj que leva a outros 3 posts, sao varios exemplos, mas nenhum resolveu a parte dos milissegundos.
http://www.guj.com.br/posts/list/71533.java

Eu fiz um codigo que funciona ±, pra isso tomei por base o exemplo desse link, o segundo post do tópico, só que fiz uma alteração pra que o cronometro seja atualizado constantemente na tela, o problema desse exemplo é que ele nao zera a variável dos milissegundos ao chegar em 1000.
http://www.guj.com.br/posts/list/71349.java

A alteração que fiz é em relação a zerar a variavel dos milissegundos, só que por conta do processamento ser muito rapido eu acho q nao tah funcionando direito, abaixo segue o codigo que fiz

[code]public class Cronometro implements Runnable {

    private long inicio;
    private long minuto;
    private long segundo;
    private long milisegundo;

    public Cronometro() {
        inicio = 0;
        milisegundo = 0;
        new Thread(this).start();
    }

    @Override
    public void run() {
        inicio = System.currentTimeMillis();
        while (!pararCronometro) {
            try {
                if (milissegundos() > 990 && milissegundos() < 1020) {
                    inicio = System.currentTimeMillis();
                    segundo = (segundo < 60) ? segundo + 1 : 0;
                    minuto = (segundo == 0) ? minuto + 1 : minuto;
                }
                jtfCronometro.setText(minuto + ":" + segundo + ":" + milissegundos());
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    //Retorna o tempo em milissegundos
    public long milissegundos() {
        synchronized (this) {
            return milisegundo = System.currentTimeMillis() - inicio;
        }
    }

    //Retorna o tempo em segundos
    public long segundos() {
        synchronized (this) {
            return segundo = milissegundos() / 1000;
        }
    }

    //Retorna o tempo em minutos
    public long minuto() {
        synchronized (this) {
            return minuto = milissegundos() / 100000;
        }
    }
}[/code]

pra iniciar essa thread eu simplesmente faço

Thread t = new Thread(new Cronometro());existe uma variavel de controle para parar a thread (pararCronometro).
eu digo que esse codigo funciona ±, pq comparando ele com o relogio do windows, tem horas em q ele se adianta (coisa de menos de um segundo), mais adianta, hehehe, e tem horas q ele se atrasa em relação ao relogio do windows, eu tive q colocar aquele if > 990 e < 1020, pra verificar se os milissegundos estao perto de 1000, pq se colocar = a 1000, ele nao percebe e passa direto (por isso q eu digo que ele nao funciona direito pq acho q o processamento é muito rapido), sem igualar novamente a variavel inicio aos milissegundos do sistema, fazendo o efeito de zerar os milissegundos. só que por conta disso ele se adianta ou atrasa um pouquinho, e mesmo assim, algumas vezes ele passa pelo if, fazendo com que a contagem dos milissegundos mostrada na tela passe de 999.

Obs: Eu deixei meu cronometro funcionando durante 5 minutos e 43 segundos, e ele estava 3 segundos atrasado em relação ao relogio do windows.

Alguem sabe fazer um cronometro com milissegundos que realmente funcione ???

Obrigado t+

Acho que o segredo é você não somar o tempo decorrido. Você calculá-lo. No início do seu cronômetro, recupere a hora inclusive com milisegundos. Depois a cada iteração do seu loop, recupere a hora novamente e compare com a hora de início.
Imagino que assim você consegue se manter sincronizado com o relógio do Windows.

e ai cara, beleza? entao, o atrazo no cronometro ocorreu pois quando vc chama o Thread.sleep(1) a jvm entende q deve esperar pelo menos 1 mili mas nada garante que ela nao va demorar 10 milis por exemplo… acho q a forma mais correta seria vc fazer o seguinte:

-Pegar os milis da JVM quando vc inicia o processo, e subtrair dos milis atuais a casa Thread.sleep(1), assim vc estará fazendo com q o que seja exibido seja a diferenca real de tempo passado e nao a quantidade de interações.
Para pegar os millis reais use:

System.currentTimeInMiles();

Espero ter ajudado :slight_smile:

dae pessoal, vlw as respostas !!
mas o q vcs sugeriram já é feito pelo método milissegundos(), só q dai tem a questao de zerar os milissegundos mostrados na tela quando atingirem 1000, e zerar os segundos quando atingirem 60… por isso eu vou somando + 1 nos segundos e nos minutos, os milissegundos eu faço a subtracao do System.currentTimeMillis() atual com o que eu peguei no inicio da thread no método milissegundos(), só q dai tem a questao de zerar os mimissegundos, por isso eu verifico se está entre 990 e 1020, pra setar novamente na variavel “inicio”, o System.currentTimeMillis(), fazendo o efeito de zerar os milissegundos…

Enfim, o atraso ou adiantamento se de dá por conta desse if, que hora está mais perto de 1020, hora mais perto de 990, por isso ele fica se adiantando ou atrasando, e nao pelo incremento que eu faço nos segundos e minutos, como vc sugeriu diogosantana…

entendo o que vc quiz dizer marcelux, mas o problema é que eu quero zerar os milissegundos e nao consigo pensar em uma maneira de fazer isso ah nao ser a que eu fiz ai em cima…

vlw a ajuda pessoal t+

[quote=cleiton herrmann]Olá pessoal

Bom, antes de mais nd, quero dizer que ja procurei aqui no guj, em outros foruns de discussao e no google, inclusive achei varios exemplos, mas nenhum resolveu a ultima parte do meu cronometro, que é os milissegundos, e que eu quero fazer um cronometro que mostre os minutos, segundos e os milissegundos, ou seja, de 0 a 999 antes de incrementar mais um nos segundos, como o cronometro de um relogio de pulso mesmo…

Bom abaixo segue um link de um post daqui do guj que leva a outros 3 posts, sao varios exemplos, mas nenhum resolveu a parte dos milissegundos.
http://www.guj.com.br/posts/list/71533.java

Eu fiz um codigo que funciona ±, pra isso tomei por base o exemplo desse link, o segundo post do tópico, só que fiz uma alteração pra que o cronometro seja atualizado constantemente na tela, o problema desse exemplo é que ele nao zera a variável dos milissegundos ao chegar em 1000.
http://www.guj.com.br/posts/list/71349.java

A alteração que fiz é em relação a zerar a variavel dos milissegundos, só que por conta do processamento ser muito rapido eu acho q nao tah funcionando direito, abaixo segue o codigo que fiz

[code]public class Cronometro implements Runnable {

    private long inicio;
    private long minuto;
    private long segundo;
    private long milisegundo;

    public Cronometro() {
        inicio = 0;
        milisegundo = 0;
        new Thread(this).start();
    }

    @Override
    public void run() {
        inicio = System.currentTimeMillis();
        while (!pararCronometro) {
            try {
                if (milissegundos() > 990 && milissegundos() < 1020) {
                    inicio = System.currentTimeMillis();
                    segundo = (segundo < 60) ? segundo + 1 : 0;
                    minuto = (segundo == 0) ? minuto + 1 : minuto;
                }
                jtfCronometro.setText(minuto + ":" + segundo + ":" + milissegundos());
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    //Retorna o tempo em milissegundos
    public long milissegundos() {
        synchronized (this) {
            return milisegundo = System.currentTimeMillis() - inicio;
        }
    }

    //Retorna o tempo em segundos
    public long segundos() {
        synchronized (this) {
            return segundo = milissegundos() / 1000;
        }
    }

    //Retorna o tempo em minutos
    public long minuto() {
        synchronized (this) {
            return minuto = milissegundos() / 100000;
        }
    }
}[/code]

pra iniciar essa thread eu simplesmente faço

Thread t = new Thread(new Cronometro());existe uma variavel de controle para parar a thread (pararCronometro).
eu digo que esse codigo funciona ±, pq comparando ele com o relogio do windows, tem horas em q ele se adianta (coisa de menos de um segundo), mais adianta, hehehe, e tem horas q ele se atrasa em relação ao relogio do windows, eu tive q colocar aquele if > 990 e < 1020, pra verificar se os milissegundos estao perto de 1000, pq se colocar = a 1000, ele nao percebe e passa direto (por isso q eu digo que ele nao funciona direito pq acho q o processamento é muito rapido), sem igualar novamente a variavel inicio aos milissegundos do sistema, fazendo o efeito de zerar os milissegundos. só que por conta disso ele se adianta ou atrasa um pouquinho, e mesmo assim, algumas vezes ele passa pelo if, fazendo com que a contagem dos milissegundos mostrada na tela passe de 999.

Obs: Eu deixei meu cronometro funcionando durante 5 minutos e 43 segundos, e ele estava 3 segundos atrasado em relação ao relogio do windows.

Alguem sabe fazer um cronometro com milissegundos que realmente funcione ???

Obrigado t+[/quote]

tenta isso

public void run() {
inicio = System.currentTimeMillis();
while (!pararCronometro) {
try {
if (milissegundos() >= 1000 ) {
inicio = System.currentTimeMillis();
segundo = (segundo < 60) ? segundo + 1 : 0;
minuto = (segundo == 0) ? minuto + 1 : minuto;
milisegundo = (milisegundo <999)? segundo + 1:0;

                }   
               
                System.out.println(minuto + ":" + segundo + ":" + milissegundos()); 
                Thread.sleep(1);   
            } catch (InterruptedException ex) {   
                ex.printStackTrace();   
            }   
        }   
    }   

nao ta ainda prox do real, mas de imediato resolve

Não entendi. Você tem o currentTimeMillis().

A diferença entre 2 currentTimeMillis() irá te retornar o número de milisegundos transcorridos entre um tempo e outro.

Então:

totalEmMilis = System.currentTimeMillis() - milisNaAtivacaoDoCronometro;

//Extraímos os milisegundos do total
milis = totalEmMilis % 1000;
//Convertemos o total para segundos
totalEmMilis = totalEmMilis / 1000;

//Extraímos os segundos do total
segundos = totalEmMilis % 60;
//Convertemos o total para minutos
totalEmMilis /= 60;

//Extraímos os minutos em 1 hora
minutos = totalEmMilis % 60;

//Convertemos o total para horas
totalEmMilis /= 60;
horas = totalEmMilis;

//Agora é só exibir
String.prinf("%02d:02d:02d.%04d", horas, minutos, segundos, milis);

nossa faiz tempo esse tópico heim, kkkk

alvorac, do jeito que vc fez, até poderia tirar o Thread.sleep(1), eu havia colocado ele pra no caso do milisegundo ser menor que 1000, dai ele entra no if milissegundos > 990 e espera um pouco, mais é como o marcelux falou, nada garante q a JVM vá esperar somente 1 mili, por isso coloquei o if milissegundos < 1020, pq nesse Thread.sleep(1), ele estava ultrapassando os 1000, mas agora vendo seu post, vi que não tem a necessidade dele, pois logo que for igual a 1000 ou ligeiramente maior, ele entra no if…

massssss…

a solução do vinigodoy é bem mais simples q a nossa, kkkk, deve ocupar bem menos processamento…
mas tem q testar e ver se com o passar do tempo, 3, 5, 10 minutos não haverá atraso no tempo, por conta do processamento da maquina…

talvez eu de uma brincada com isso hj a noite, tenho q terminar o ppt pra apresentar a TCC…
vlw t+ pessoal

[quote=cleiton herrmann]é a solução do vinigodoy é bem mais simples q a nossa, kkkk
mas tem q testar e ver se com o passar do tempo, 3, 5, 10 minutos não haverá atraso no tempo, por conta do processamento da maquina…[/quote]

O atraso médio na minha solução será de aproximadamente 10ms na maior parte dos SOs 32 bits, 1ms nas distros mais novas do linux e nos SOs de 64bits. Note que, como sempre o System.currentTimeMillis() é chamado, não há acumulo de imprecisão em variáveis temporárias.

O drift rate pode variar de máquina para máquina, já que os cristais de quartzo não pulsam exatamente na mesma velocidade. Se você estiver trabalhando com sincronização de relógios, talvez você tenha que usar algum algoritmo para reajustar o relógio de tempos em tempos. No livro de sistemas distribuídos do Colouris esse algoritmo é descrito em detalhes. Duvido muito que você consiga uma precisão maior que a do timer do SO, a menos que você vá rodar por muitas horas a fio.

Interessante vinigodoy, vlw pela explicação ai !!!
não sei quanto aos colegas, mas eu não vou me dedicar tanto assim nisso, era mais por curiosidade mesmo…

Att