gr8vyguy@Blogjava

用JNI实现高精度的Java计时器(Java Timer)

在Java程序中,我们可以用System.currentTimeMillis()来计时,但是精度不高,在我的机子(Pentium M 1.5GHz, WinXP)上,精度小于10ms。通过一个简单的Java程序,我们可以测试

public static void main(String[] args) {
        long begin = System.currentTimeMillis();
        
long current;
        
while (begin == (current = System.currentTimeMillis()))
            ;
        System.out.println((current 
- begin) + " ms");
}

System.currentTimeMillis()大约10ms才变化一次。

10ms的精度在很多情况下是不够用的,比如开发射击类游戏等等。而PC中自身计时器的精度要高很多,即使是WindowsXP提供的计时器也要比Java的System.currentTimeMillis()高太多了。比如用Win32的QueryPerformanceCounter函数,在我的机子上可以得到1ns的精度。计算机越发展,软件利用硬件的程度和效率却越来越差,这一点在Java的身上表现的尤其严重,随着多核CPU的普及,这个问题还要进一步严重。

言归正传,我们来讲怎么利用QueryPerformanceCounter来实现一个native的Java计时器.
package cn.pandaoen.timer;

/**
 * A Timer class uses native methods to measure times.
 *  
 * 
@author pan
 
*/
public class Timer {

    
private long prev;

    
public void reset() {
        prev 
= QueryPerformanceCounter();
    }

    
/**
     * 
@return the duration in ms from the point of reset()
     
*/
    
public double getDuration() {
        
long current = QueryPerformanceCounter();
        
return (current - prev) / frequency;
    }

    
static final double frequency;

    
static native long QueryPerformanceFrequency();

    
static native long QueryPerformanceCounter();

    
static {
        System.loadLibrary(
"extension");
        frequency 
= QueryPerformanceFrequency() / 1000.0;
    }
}

Native的代码
#include "cn_pandaoen_timer_Timer.h"
#include 
<windows.h>

JNIEXPORT jlong JNICALL
Java_cn_pandaoen_timer_Timer_QueryPerformanceFrequency(JNIEnv 
*e, jclass cls)
{
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(
&frequency);
    
return (jlong)frequency.QuadPart;
}

JNIEXPORT jlong JNICALL
Java_cn_pandaoen_timer_Timer_QueryPerformanceCounter(JNIEnv 
*e, jclass cls)
{
    LARGE_INTEGER counter;
    QueryPerformanceCounter(
&counter);
    
return (jlong)counter.QuadPart;
}

用法是,在开始点调用的timer.reset(), 结束时调用timer.getDuration()得到所用的时间,单位是ms.一个timer的instance可以多次使用.

下面我们来看看这个计时器都多高的精度。
public class TimerTest {
    
public static void main(String[] args) {
        
long f = Timer.QueryPerformanceFrequency();
        
long p = Timer.QueryPerformanceCounter();
        
long c;
        
while (p == (c = Timer.QueryPerformanceCounter()))
            ;
        System.out.println(((c 
- p) * 1000000 / f) + " ns");
    }
}
在同样的系统下,我得到1ns的精度.

这种方法的一个缺点当然是,它现在还只能在Windows下使用,如果有朋友愿意帮忙实现别的系统下的native代码的话,我会非常感谢的。

代码  timer.rar

转载请保留http://www.blogjava.net/xilaile/archive/2007/02/24/100441.html

posted on 2007-02-23 22:49 gr8vyguy 阅读(7828) 评论(3)  编辑  收藏 所属分类: Java

评论

# re: 用JNI实现高精度的Java计时器(Java Timer)[未登录] 2007-11-15 12:17 liu

没有cn_pandaoen_timer_Timer.h
timer.rar的代码下不下来,能否发到我的邮箱,多谢
crazycowliu@sina.com  回复  更多评论   

# re: 用JNI实现高精度的Java计时器(Java Timer)[未登录] 2007-11-15 12:46 liu

不好意思,才知道要用javah生成.h文件...  回复  更多评论   

# re: 用JNI实现高精度的Java计时器(Java Timer)[未登录] 2013-07-30 17:19 Kent

代码结果是微秒级,不是纳秒级。
测试代码
f = Timer.QueryPerformanceFrequency();
是每秒counter数,并不是毫秒。
故乘1000000表示微秒,不是纳秒。
  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
<2007年2月>
28293031123
45678910
11121314151617
18192021222324
25262728123
45678910

导航

统计

公告

  • 转载请注明出处.
  • msn: gr8vyguy at live.com
  • 常用链接

    留言簿(9)

    随笔分类(68)

    随笔档案(80)

    文章分类(1)

    My Open Source Projects

    搜索

    积分与排名

    最新评论