Programming/Java

[Java] currentTimeMillis() nanoTime() Instant.now() uuid

owls 2024. 5. 31. 16:09
728x90

Java는 시간 값을 측정하는 두 가지 기본 메소드를 제공한다. 

 

System.currentTimeMillis()는 현재 시간을 밀리초 단위로 반환한다.
System.nanoTime()은 현재 시간을 나노초 단위로 반환한다.

 

두 가지 방법은 상당한 차이가 있다.

 

시간은 계속 흘러가기 때문에 시간을 고유한 값으로 사용하는 경우가 많다. 이런 경우 어떤 메소드로 사용해야 할지 알아보자.

 

System.currentTimeMillis()

밀리초 단위 사용(ms)

1970년 1월 1일 UTC시작 시점을 기준으로 현재까지 계산

시스템 시간을 참조(운영체제의 시간 값을 기준)

-> 날짜와 날짜 사이의 갭을 구할 때 사용

1초 = 1000밀리초

 

장점

1. thread safe

2. 항상 epoch이후 경과된 절대 시간을 반환한다. 

  (1970년 1월 1일 00:00 이후 밀리초 수)

3. 실행하는데 더 적은 클록 주기를 사용 (약 5~6 CPU 클록)

4. 기준점(epoch)이 고정되어 있으므로 더 정확한 시간을 제공

 

 

 

System.nanoTime()

Java 1.5부터 도입

나노초 단위 사용(ns)

기준 시점에서 경과 시간을 측정

시스템 시간과는 무관

JVM이 시작 시간 ~ 종료 시간을 반환

-> 개발한 프로그램의 실행 시간을 구할 때 (성능 측정)사용

1초 = 1e+9 ( 10억 분의 1초)

 

 

Instant.now()

Java1.8부터 도입된 시간 객체

1970년 1월 1일 UTC시작 시점을 기준으로 현재까지 계산

시스템 시간을 참조(운영체제의 시간 값을 기준)

밀리초(toMillis), 초(getSeconds) 모두 계산 가능

 

 

UUID

Universally Unique Identifier

범용 고유 식별자를 의미하며 중복이 되지 않는 유일한 값을 구성하고자 할 때 주로 사용되는 고유 식별자를 의미한다.

주로 세션 식별자, 쿠키 값, 무작위 데이터베이스 키 등에 사용된다.

 

UUID는 16바이트(128비트)형태의 구조를 가지며 하나의 UUID길이는 36자리이며 "4개의 하이픈(-)"과 "32개의 16진수 문자열"로 구성되어 있다.

 

구조 길이
(byte)
길이(hex) 길이
(bits)
내용
Low Time 4 8 32 시간의 low 32비트를 부여하는 정수
Mid time 2 4 16 시간의 middle 16비트를 부여하는 정수
Mid time + version 2 4 16 최상위 비트에서 4비트 "version", 그리고 시간의 high 12비트
Clock sequence and variant 2 4 16 최상위 비트에서 1-3비트는 UUID의 레이아웃형식, 그리고 13-15비트 클럭 시퀀스
Node 6 12 48 48비트 노드 id

 

 

버전

버전 설명 특징
UUID
Version1
“현재 시간”과 “랜덤한 MAC 주소”를 기반으로 생성
timestamp + MAC주소
유일성이 보장되지만 보안에 취약함.
UUID
Version2
이전 버전 1과 유사하지만 시퀀스 번호 대신 POSIX UID(사용자 ID)를 사용하여 생성
timestamp + MAC주소 + DCE보안
현재는 거의 사용하지 않음.
UUID
Version3
해시 함수인 “MD5 해시”를 기반으로 이름과 네임스페이스에 대한 조합으로 생성
name-based + MD5해시
암호화 해시 함수를 사용하여 생성하므로 보안성이 높음.
이름과 네임스페이스가 같으면 같은 UUID가 생성됨
UUID
Version4
“랜덤한 값”을 기반으로 생성 보안성이 높고 생성속도가 빠름.
가장 많이 사용
UUID
Version5
이전 버전 3과 유사하지만 “SHA-1 해시”를 사용하여 생성
name-based + SHA-1 해시
 보안에 취약하다는 단점
(SHA-1 해시는 보안 취약점 발견) 

 

java.uitl.UUID클래스의 randomUUID() 메소드를 호출하면 버전4 UUID 값을 가진 객체가 반환된다.

 

중복이 발생할 확률

System.currentTimeMillis()

현재 시간을 밀리초 단위로 반환한다.

밀리초 단위의 시간 값이기 때문에, 매우 빠르게 연속적으로 호출하면 중복될 가능성이 있다.

중복이 발생할 수 있는 경우

타이머 해상도 대부분의 현대적인 시스템은 밀리초 해상도를 제공하지만, 실제 해상도는 운영 체제와 하드웨어에 따라 다를 수 있다.
호출 빈도 연속적으로 매우 빠르게 호출할 경우, 같은 밀리초 안에 여러 번 호출될 가능성이 높아진다.

 

이 두 가지 요소를 기반으로 System.currentTimeMillis() 의 중복 발생 확률을 추정해보자.

1초 동안 100,000번의 호출을 할 때 중복 발생 확률은 0.993 (99.3%) 이다.

따라서,  System.currentTimeMillis() 는 밀리초 단위의 시간 값을 반환하기 때문에 매우 빈번하게 호출하는 경우 중복이 발생할 가능성이 매우 높다. 

일반적으로 이 메서드는 시간이 중요한 로그 기록이나 시간 측정에 사용되며, 고유한 식별자가 필요한 경우에는 적합하지 않다. 

고유한 식별자가 필요한 경우 "UUID"나 다른 고유 식별자 생성 방법을 사용하는 것이 좋다.

 

● System.nanoTime()

 현재 JVM의 시간 값을 나노초 단위로 반환한다. 절대적이 시간 값이 아닌 상대적인 시간 값으로, JVM의 시작 시간 이후 경과한 시간을 나노초 단위로 측정한 값이다.

JVM의 해상도와 시스템 성능에 의존하기 때문에 하드웨어와 운영 체제에 따라 시간 값이 중복될 수 있는 가능성이 존재한다.

 중복이 발생할 수 있는 경우

타이머 해상도 많은 시스템에서 타이머 해상도는 나노초보다 훨씬 낮다. 일부 시스템에서는 마이크로초, 밀리초 단위로 측정될 수 있다.
호출 빈드 "System.nanoTime()"을 매우 빠르게 반복 호출하면, 시스템 타이머의 해상도 한계 때문에 같은 값을 반환할 확률이 높아진다.
시스템 성능 시스템의 성능, 특히 CPU의 클럭 속도와 시스템 타이머의 정확성에 따라 값이 중복될 가능성이 다르다.

 

 

● UUID

일반적으로 UUID는 2^128개의 고유한 값을 가질 수 있다.

UUID로 많이 사용하는 version4의 중복이 발생할 확률:

1백만 개의 UUID 생성 시 중복 발생 확률은 약 2.71X10^(-18) (즉, 0.000000000000000271)

중복이 발생할 가능성은 거의 없다고 본다.

 

정리

정교한 시간 성능을 측정하기 위해서는 nanoTIme()을 추천한다.

시스템 시간과 상관없이 정확한 시간 측정이 가능하다.

 

하지만 nanoTime()은 일부 서버 환경에서는 정확하지 않다.

 

이때는 currentTimeMillis(), Instant.now()를 활용할 수 있다.

시스템 시간을 활용하면 현재 시각을 기준으로 다양한 계산이 가능하다.

(운영체제의 시간 설정이 일정하다는 전제 조건이 필요함)

 

고유한 식별자가 필요한 경우 "UUID" 또는 다른 고유 식별자 생성 방법을 사용하는 것이 좋다.

 

 

 

 

참고

https://pradeesh-kumar.medium.com/java-system-nanotime-vs-system-currenttimemillis-604f59555561

 

https://devfoxstar.github.io/java/measure-elapsed-time/#currenttimemillis

 

https://adjh54.tistory.com/142#google_vignette

 

https://adjh54.tistory.com/142

 

 

 

 

 

 

 

728x90