닉네임 뒤에 난수 식별자 붙이는 기능을 구현하면서 늘 사용하던 Random 객체를 사용했다.
근데 어느 친절한 개발자 분께서 "Random 클래스"의 문제점이 뭐냐고 물어보셨다.
네? Random class에 문제점이 있었나요? 바로 어떤 문제점이 있는지 찾아봤다.
1. 보안
Random 객체를 사용할 경우 생각보다 난수 같지 않은 난수를 얻는다(특징이 반복되는 난수들이 생성된다). 그래서 SecureRandom 객체를 사용해서 더 난수에 가까운 값을 만들 수 있다. 비교적 난수를 예측하기 쉬운 Random보다 SecureRandom 객체를 사용하는 것이 좋다.
라고 하면 좋겠지만 SecureRandom 객체 역시 사용하지 않는 게 좋다. 보안 목적을 떠나서 SecureRandom 객체 역시 Random 객체와 같은 문제를 가지고 있기 때문이다.
Random 객체와 SecureRandom 객체에는 대체 어떤 문제가 있는 걸까?
2. 동시성 ⭐️⭐️⭐️⭐️⭐️
Random 함수와 동시성
바로 밑밑밑에 동시성 문제 관련 글을 적어놓고 동시성 문제가 발생하는 Random 객체를 사용하고 있었다.
내가 구현하려는 회원가입 로직은 다음과 같다.
- 회원가입 요청이 들어온다.
- 닉네임 뒤에 식별자를 붙이기 위해 Random 객체를 호출하여 4자리 난수를 생성한다.
- 4자리 난수를 닉네임 뒤에 붙인 후 Member 객체 생성한다.
처음에 구현한 난수 생성 코드를 보자
내가 작성한 코드지만 아주 익숙한 코드다. Random 객체를 사용해 봤다면 한 번쯤은 봤을 법한 코드다.
그럼 이제 nexInt() 코드를 파헤쳐보자
next()를 호출하여 반환한다. 바로 next() 코드를 파헤쳐보자
next 메서드 안에서 연산이 끝난 후 seed가 수정된다. 이때 여러 스레드가 해당 seed에 동시에 접근하면 어떻게 될까?
- 스레드 A가 sss 시드로 Random 연산 수행
- 스레드 B가 sss 시드로 Random 연산 수행
- 스레드 A가 sss 시드를 ddd 시드로 변경
- 스레드 B가 sss 시드를 변경하려고 하는데 없..다?
동시성 문제가 발생한다. 이를 해결하기 위해서는 ThreadLocalRandom 객체를 사용해야 한다.
코드는 아래와 같다.
ThreadLocalRandom 객체를 사용하려면 current()를 호출해야 한다. 왜냐하면 스레드에 대해 별도의 난수 생성기가 필요하기 때문에 current() 메서드를 사용하여 현재 스레드에 대한 ThreadLocalRandom 객체를 생성하기 때문이다.
ThreadLocal은 워낙 유명한 동시성 문제 해결박사다. ThreadLocal이 스레드마다 저장소를 만들어 동시성 문제를 해결하는 것과 같이, ThreadLocalRandom 객체는 각 스레드마다 Random 객체를 만들어 동시성 문제를 해결한다.
⭐️ 결론 ⭐️
ThreadLocalRandom 객체를 사용하자
'Dev > Java' 카테고리의 다른 글
[Java] 직렬화, 역직렬화, 그리고 Getter (0) | 2024.05.23 |
---|---|
[Java] Value Object와 Entity에 대한 소신 정리 (0) | 2024.05.19 |
[Java] 값 객체(Value Object)란 도대체 뭘까? (0) | 2024.05.12 |
[Java] 필드 동기화로 인한 동시성 문제 해결하기 (by. ThreadLocal) (0) | 2024.05.03 |
[Java] Web server failed to start. Port 5000 was already in use. (MacOS) (1) | 2024.01.24 |