H5W3
当前位置:H5W3 > 其他技术问题 > 正文

用JNI实现一个高精度的Java计时器

    在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 JNICALLJava_cn_pandaoen_timer_Timer_QueryPerformanceFrequency(JNIEnv *e, jclass cls){    LARGE_INTEGER frequency;    QueryPerformanceFrequency(&frequency);    return (jlong)frequency.QuadPart;}JNIEXPORT jlong JNICALLJava_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代码的话,我会非常感谢的。

本文地址:H5W3 » 用JNI实现一个高精度的Java计时器

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址