在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的精度在很多情況下是不夠用的,比如開發(fā)射擊類游戲等等。而PC中自身計時器的精度要高很多,即使是WindowsXP提供的計時器也要比Java的System.currentTimeMillis()高太多了。比如用Win32的QueryPerformanceCounter函數(shù),在我的機子上可以得到1ns的精度。計算機越發(fā)展,軟件利用硬件的程度和效率卻越來越差,這一點在Java的身上表現(xiàn)的尤其嚴(yán)重,隨著多核CPU的普及,這個問題還要進一步嚴(yán)重。
言歸正傳,我們來講怎么利用QueryPerformanceCounter來實現(xiàn)一個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;
}
用法是,在開始點調(diào)用的timer.reset(), 結(jié)束時調(diào)用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");
}
}
在同樣的系統(tǒng)下,我得到1ns的精度.
這種方法的一個缺點當(dāng)然是,它現(xiàn)在還只能在Windows下使用,如果有朋友愿意幫忙實現(xiàn)別的系統(tǒng)下的native代碼的話,我會非常感謝的。
代碼
timer.rar
轉(zhuǎn)載請保留
http://www.tkk7.com/xilaile/archive/2007/02/24/100441.html