用JNI實(shí)現(xiàn)高精度的Java計(jì)時(shí)器(Java Timer)
在Java程序中,我們可以用System.currentTimeMillis()來(lái)計(jì)時(shí),但是精度不高,在我的機(jī)子(Pentium M 1.5GHz, WinXP)上,精度小于10ms。通過一個(gè)簡(jiǎn)單的Java程序,我們可以測(cè)試public static void main(String[] args) {
long begin = System.currentTimeMillis();
long current;
while (begin == (current = System.currentTimeMillis()))
;
System.out.println((current - begin) + " ms");
}
long begin = System.currentTimeMillis();
long current;
while (begin == (current = System.currentTimeMillis()))
;
System.out.println((current - begin) + " ms");
}
System.currentTimeMillis()大約10ms才變化一次。
10ms的精度在很多情況下是不夠用的,比如開發(fā)射擊類游戲等等。而PC中自身計(jì)時(shí)器的精度要高很多,即使是WindowsXP提供的計(jì)時(shí)器也要比Java的System.currentTimeMillis()高太多了。比如用Win32的QueryPerformanceCounter函數(shù),在我的機(jī)子上可以得到1ns的精度。計(jì)算機(jī)越發(fā)展,軟件利用硬件的程度和效率卻越來(lái)越差,這一點(diǎn)在Java的身上表現(xiàn)的尤其嚴(yán)重,隨著多核CPU的普及,這個(gè)問題還要進(jìn)一步嚴(yán)重。
言歸正傳,我們來(lái)講怎么利用QueryPerformanceCounter來(lái)實(shí)現(xiàn)一個(gè)native的Java計(jì)時(shí)器.
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;
}
}
/**
* 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;
}
#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ǎn)調(diào)用的timer.reset(), 結(jié)束時(shí)調(diào)用timer.getDuration()得到所用的時(shí)間,單位是ms.一個(gè)timer的instance可以多次使用.
下面我們來(lái)看看這個(gè)計(jì)時(shí)器都多高的精度。
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的精度.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");
}
}
這種方法的一個(gè)缺點(diǎn)當(dāng)然是,它現(xiàn)在還只能在Windows下使用,如果有朋友愿意幫忙實(shí)現(xiàn)別的系統(tǒng)下的native代碼的話,我會(huì)非常感謝的。
代碼 timer.rar
轉(zhuǎn)載請(qǐng)保留http://www.aygfsteel.com/xilaile/archive/2007/02/24/100441.html
posted on 2007-02-23 22:49 gr8vyguy 閱讀(7857) 評(píng)論(3) 編輯 收藏 所屬分類: Java