System.currentTimeMillis 및 System.nanoTime


379

정확도 대. 정도

게임에서 객체의 위치를 ​​업데이트 할 때 System.currentTimeMillis () 또는 System.nanoTime ()을 사용해야하는지 여부를 알고 싶습니다 . 그들의 움직임의 변화는 마지막 호출 이후 경과 시간에 직접 비례하며 가능한 한 정확하고 싶습니다.

다른 운영 체제 사이에 심각한 시간 해결 문제가 있음을 읽었습니다 (즉, Mac / Linux의 해상도는 거의 1ms이고 Windows의 해상도는 50ms입니다 ??). 나는 주로 Windows에서 내 앱을 실행하고 있으며 50ms 해상도는 매우 정확하지 않은 것 같습니다.

내가 나열된 두 가지보다 더 나은 옵션이 있습니까?

제안이나 의견이 있으십니까?


81
nanoTime일반적으로 currentTimeMillis보다 훨씬 정확하지만 비교적 비싼 통화입니다. currentTimeMillis()nanoTime은 몇 가지 (5-6) CPU 클럭에서 실행되며 기본 아키텍처에 따라 다르며 100 + CPU 클럭이 될 수 있습니다.
bestsss

10
당신은 모두 Windows가 일반적으로 1000ms / 64의 시간 단위 세분성을 가지고 있다는 것을 알고 있습니까? 15.625ms 또는 15625000nanoseconds입니다!

7
백개의 추가 클럭 사이클이 게임에 영향을 줄 것이라고 생각하지 않으며 트레이드 오프가 그만한 가치가 있다고 생각합니다. 게임 업데이트마다 메소드를 한 번만 호출 한 다음 mem에 값을 저장해야하므로 오버 헤드가 많이 발생하지 않습니다. 다른 플랫폼의 세분성에 대해서는 전혀 모른다.
aglassman 2016 년

9
Windows의 DEFAULT timelice 세분성은 1000ms / 64입니다. 기본 timeBeginPeriod API를 통해이를 늘릴 수 있습니다. 최신 PC에는 기본 타이머 외에도 고해상도 타이머가 있습니다. QueryPerformanceCounter 호출을 통해 고해상도 타이머에 액세스 할 수 있습니다.
로빈 데이비스

2
- @Gohan이 문서의 내부 동작에 대한 내용이수록 System.currentTimeMillis(): pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.html
아틸라 Tanyi에게

답변:


320

경과 시간 을 매우 정밀하게 측정 하려면을 사용하십시오 System.nanoTime(). System.currentTimeMillis()에포크 이후 가장 정확한 경과 시간을 밀리 초 단위로 System.nanoTime()제공 하지만 임의의 지점에 비해 나노초 단위의 정확한 시간을 제공합니다.

Java 문서에서 :

public static long nanoTime()

사용 가능한 가장 정확한 시스템 타이머의 현재 값을 나노초 단위로 반환합니다.

이 방법은 경과 시간을 측정하는 데만 사용할 수 있으며 다른 시스템 또는 벽시계 시간 개념과 관련이 없습니다. 반환 된 값은 고정되었지만 임의의 원점 시간 (나중에 값이 음수 일 수 있음) 이후 나노초를 나타냅니다 . 이 방법은 나노초 정밀도를 제공하지만 반드시 나노초 정확도는 아닙니다. 값이 얼마나 자주 변경되는지는 보증하지 않습니다. 약 292 년 (2 63 나노초)을 초과하는 연속 호출의 차이는 숫자 오버플로로 인해 경과 시간을 정확하게 계산하지 않습니다.

예를 들어, 일부 코드를 실행하는 데 걸리는 시간을 측정하려면 다음을 수행하십시오.

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

자세한 정보는 JavaDoc System.nanoTime ()JavaDoc System.currentTimeMillis () 를 참조하십시오.


20
정확성과 정밀도의 차이를 알고 있습니까? 나노초 정밀도까지 정확한 방법은 없습니다.
mmcdole

6
죄송합니다. 정확한 의미였습니다. 나는이 용어를 느슨하게 사용하고 있었지만 혼동스럽고 단어를 잘못 사용하는 데 동의했다.
dancavallaro

4
@dancavallaro, 정보 주셔서 감사합니다. 마음에 들지 않으면 문서의 인용문을 포함하도록 답변을 편집하고 링크를 수정했습니다
mmcdole

135
이 답변은 nanoTime ()을 선택하는 데 기술적으로 정확하지만 매우 중요한 점에서 완전히 빛납니다. 의사가 말했듯이 nanoTime ()은 정밀 타이머입니다. currentTimeMillis ()는 타이머가 아니며 "벽시계"입니다. nanoTime ()은 항상 양의 경과 시간을 생성하고 currentTimeMillis는 그렇지 않습니다 (예 : 날짜를 변경하거나 윤초 등을 맞출 경우 등). 이는 일부 유형의 시스템에서 매우 중요한 차이점입니다.
charstar

11
사용자 변경 시간과 NTP는 확실하지만 currentTimeMillisDST로 인해 왜 변경됩니까? DST 스위치는 에포크를 지나친 초 수를 변경하지 않습니다. "벽시계"일 수도 있지만 UTC를 기준으로 한 것입니다. 시간대 및 DST 설정에 따라 현지 시간으로 변환 할 내용을 결정해야합니다 (또는 다른 Java 유틸리티를 사용하여이를 수행).
Shadow Man

100

아무도 이것을 언급하지 않았기 때문에…

System.nanoTime()다른 스레드 간 호출 결과를 비교하는 것은 안전하지 않습니다 . 스레드의 이벤트가 예측 가능한 순서로 발생하더라도 나노초의 차이는 양수 또는 음수 일 수 있습니다.

System.currentTimeMillis() 스레드간에 사용하기에 안전합니다.


4
Windows에서 단지에 따라 SP2 때까지 보관 유지하는 : stackoverflow.com/questions/510462/...
피터 슈미츠

3
글쎄, 당신은 매일 새로운 것을 배웁니다. 그러나 과거에는 안전하지 않았기 때문에 (스레드 전체에서 넌센스 판독 값을 확실히 반환 함) 그러한 사용은 여전히 ​​사양 외부에 있으므로 피해야합니다.
gubby

4
@ jgubby : 매우 흥미 롭습니다 ... 다른 스레드간에 System.nanoTime () 호출의 결과를 비교하는 것이 안전하지 않은 지원에 대한 참조 무엇입니까? 다음 링크를 참조하십시오. bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519418 docs.oracle.com/javase/7/docs/api/java/lang/…
user454322

15
여기에 언급 된 docs.oracle.com/javase/7/docs/api/java/lang/… 설명을 보면 nanoTime에서 반환 된 값의 차이가 동일한 경우에만 비교에 유효한 것처럼 보입니다. JVM -The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.
Tuxdude

7
JavaDoc의nanoTime() 내용 : Java 가상 머신 인스턴스에서이 메소드의 모든 호출에 동일한 원점이 사용됩니다. 다른 가상 머신 인스턴스는 다른 오리진을 사용할 수 있습니다. 이는이 있음을 의미 않는 스레드에서 동일한을 반환합니다.
Simon Forsberg

58

Arkadiy에 의한 업데이트 : System.currentTimeMillis()Oracle Java 8의 Windows 7에서 보다 정확한 동작을 관찰했습니다 . 시간은 1 밀리 초 정밀도로 반환되었습니다. OpenJDK의 소스 코드는 변경되지 않았으므로 더 나은 동작을 일으키는 원인을 모르겠습니다.


Sun의 David Holmes는 2 년 전에 Java 타이밍 API (특히 System.currentTimeMillis()System.nanoTime()), 사용시기 및 내부 작동 방식에 대해 자세히 살펴 보는 블로그 기사를 게시했습니다 .

핫스팟 VM 내부 : 시계, 타이머 및 예약 이벤트-1 부-Windows

timed 대기 매개 변수가있는 API에 대해 Windows에서 Java가 사용하는 타이머의 매우 흥미로운 측면 중 하나는 다른 API 호출이 수행 된 내용에 따라 타이머의 해상도가 변경 될 수 있다는 것입니다. . 그는 사용 Thread.sleep()하면이 해상도 변경이 발생 하는 예를 보여줍니다 .


1
@ Arkadiy : 업데이트의 진술에 대한 출처가 있습니까?
Lii

@Lii-불행히도 이 질문에서 코드를 실행하면 발생합니다 : stackoverflow.com/questions/34090914/… . 이 코드는 자바 8 자바 7 일 MS 정밀도와 15ms의 정밀도를 생산

2
OpenJDK의 hotspot / src / os / windows / vm / os_windows.cpp에서 os :: javaTimeMillis에 currentTimeMillis를 추적했습니다 ( hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/os/… ) . 여전히 GetSystemTimeAsFileTime 인 것처럼 보이므로 변경이 어디서 오는지 알 수 없습니다. 또는 그것이 유효하다면. 사용하기 전에 테스트하십시오.

동작 변경 GetSystemTimeAsFileTime은 XP와 7에서 작동 방식을 변경 한 결과입니다 . 자세한 내용은 여기 를 참조 하십시오 .

11

System.nanoTime()이전 JVM에서는 지원되지 않습니다. 그게 걱정이라면currentTimeMillis

정확성과 관련하여 거의 정확합니다. 일부 Windows 컴퓨터에서는currentTimeMillis() 약 10ms (50ms 아님)의 해상도를 갖습니다. 왜 그런지 잘 모르겠지만 일부 Windows 시스템은 Linux 시스템만큼 정확합니다.

나는 과거에 GAGETimer 를 적당한 성공으로 사용했습니다.


3
"이전 JVM"은 어느 것입니까? 자바 1.2 또는 무엇인가?
Simon Forsberg

1
System.nanoTime ()은 2004 년 Java 1.5에서 도입되었습니다. 2013 년 Java 1.4 확장 지원이므로 System.nanoTime ()을 신뢰할 수 있으며이 답변은 최신이 아닙니다.
Dave L.

9

다른 사람들이 말했듯이 currentTimeMillis는 일광 절약 시간, 시간 설정 변경, 윤초 및 인터넷 시간 동기화로 인해 변경되는 시계 시간입니다. 앱이 단시간 증가하는 경과 시간 값에 의존하는 경우 대신 nanoTime을 선호 할 수 있습니다.

게임을하는 동안 플레이어가 시간 설정을 다루지 않을 것이라고 생각할 수도 있습니다. 그러나 인터넷 시간 동기화 또는 원격 데스크톱 사용자로 인한 중단을 과소 평가하지 마십시오. nanoTime API는 이러한 종류의 중단에 영향을받지 않습니다.

시계 시간을 사용하고 싶지만 인터넷 시간 동기화로 인한 불연속을 피하려면 Meinberg와 같은 NTP 클라이언트를 고려하십시오. Meinberg는 시계를 주기적으로 재설정하는 대신 클럭 속도를 0으로 조정합니다.

나는 개인적인 경험에서 말합니다. 내가 개발 한 날씨 응용 프로그램에서 무작위로 발생하는 풍속 급증이 발생했습니다. 일반적인 PC에서 시계 시간 동작으로 인해 타임베이스가 중단되고 있음을 깨닫는 데 시간이 걸렸습니다. nanoTime 사용을 시작했을 때 모든 문제가 사라졌습니다. 일관성 (monotonicity)은 원시 정밀도 또는 절대 정확도보다 응용에 더 중요했습니다.


19
"currentTimeMillis는 일광 절약 시간 제로 인해 변경되는 시계 시간입니다." ...이 문장이 거짓인지 확인하십시오. System.currentTimeMillis()1970 년 1 월 1 일 자정 (UTC) 인 Unix / Posix Epoch 이후 경과 시간 (밀리 초)을보고합니다. UTC는 일광 절약 시간 제로 조정되지 않으므로 일광 절약 시간 제로 현지 시간대를 추가하거나 현지 시간에 오프셋을 적용하면이 값이 오프셋되지 않습니다. 또한 Java Time Scale은 윤초를 매끄럽게하여 일 수가 86,400 초로 계속 표시되도록합니다.
scottb

5

예, 그러한 정밀도가 필요한 경우 사용하십시오 System.nanoTime() 하지만 Java 5+ JVM이 필요하다는 점에 유의하십시오.

XP 시스템 에서 다음 코드를 사용하여 시스템 시간이 100 마이크로 초 278 나노초 이상으로보고되었습니다 .

private void test() {
    System.out.println("currentTimeMillis: "+System.currentTimeMillis());
    System.out.println("nanoTime         : "+System.nanoTime());
    System.out.println();

    testNano(false);                                                            // to sync with currentTimeMillis() timer tick
    for(int xa=0; xa<10; xa++) {
        testNano(true);
        }
    }

private void testNano(boolean shw) {
    long strMS=System.currentTimeMillis();
    long strNS=System.nanoTime();
    long curMS;
    while((curMS=System.currentTimeMillis()) == strMS) {
        if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
        }
    if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
    }

4

게임 그래픽 및 부드러운 위치 업데이트를 위해서는 System.nanoTime()대신System.currentTimeMillis() . 게임에서 currentTimeMillis ()에서 nanoTime ()으로 전환했으며 동작의 부드러움이 크게 개선되었습니다.

1 밀리 초는 이미 정확해야하는 것처럼 보이지만 시각적으로는 그렇지 않습니다. nanoTime()개선 할 수 있는 요소 는 다음과 같습니다.

  • 벽시계 해상도 미만의 정확한 픽셀 위치
  • 원하는 경우 픽셀 간 앤티 앨리어싱 기능
  • Windows 벽시계 부정확
  • 클럭 지터 (벽시계가 실제로 앞으로 움직일 때의 불일치)

다른 답변에서 알 수 있듯이 nanoTime은 반복적으로 호출하면 성능 비용이 발생합니다. 프레임 당 한 번만 호출하고 동일한 값을 사용하여 전체 프레임을 계산하는 것이 가장 좋습니다.


1

나는 nanotime에 대한 좋은 경험을 가지고 있습니다. JNI 라이브러리를 사용하여 벽시계 시간을 2 초 (에포크 이후 초와 그 초 안에 나노초)로 제공합니다. Windows 및 Linux 용으로 사전 컴파일 된 JNI 파트와 함께 사용할 수 있습니다.


1

System.currentTimeMillis()이 방법은 시스템의 시스템 실시간 시계 변경에 민감하므로 경과 시간에 안전하지 않습니다. 사용해야합니다System.nanoTime . Java 시스템 도움말을 참조하십시오.

nanoTime 방법에 관하여 :

..이 방법은 나노초 정밀도를 제공하지만 반드시 나노초 분해능 일 필요는 없습니다 (즉, 값이 얼마나 자주 변경되는지). 해상도가 적어도 currentTimeMillis ()의 분해능보다 우수하다는 것 외에는 보장 할 수 없습니다.

System.currentTimeMillis()경과 시간 을 사용 하면 음수 일 수 있습니다 (뒤로 <-미래로).


-3

여기서 한 가지는 nanoTime 방법의 불일치입니다. 동일한 입력에 대해 매우 일관된 값을 제공하지 않습니다 .currentTimeMillis는 성능 및 일관성 측면에서 훨씬 뛰어나고 nanoTime만큼 정확하지는 않지만 오류의 여백이 적습니다. 따라서 그 가치가 더 정확합니다. 따라서 currentTimeMillis를 사용하는 것이 좋습니다.


6
다른 답변과 의견에서 언급했듯이 currentTimeMillis는 시스템 클럭 변경에 따라 달라질 수 있으므로 JVM의 이전 이벤트 이후 경과 시간을 계산하기에 적합하지 않습니다.
duelin markers
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.