static 메소드, 변수의 Thread safe, unsafe
1. static
자주, 반복적으로 사용하는 메소드를 개발할 때 고민해봐야 하는 것이 static의 사용입니다.
static 의 경우 new 키워드로 생성하여 Heap 에 저장되는 일반 객체와 달리,
GC의 대상이 되지 않는 Data 영역에 저장됩니다.
이는 어플리케이션이 종료될 때 까지 메모리에서 해제되지 않음을 의미 합니다.
static 은 잘 사용하면 매우 유용하지만, 잘못 사용하거나 남발하게 되면 어플리케이션의 퍼포먼스에
악영양을 미치기 때문에 적절하게 사용해야 합니다.
link : https://aljjabaegi.tistory.com/636
2. Thread safe
static은 위에서 말씀드린 것과 같이 한번 메모리에 올라가게 되면 어플리케이션이 종료 될 때 까지
메모리에서 해제되지 않습니다. 다르게 말하면, 접근하는 모든 Thread가 공유한다는 말이 됩니다.
특히, Multi Thread 환경에서 같은 static 변수나 메소드에 동시에 접근하게 되면 원하지 않은 결과를
얻을 수 있습니다. '이를 Thread safe 하지 않다 (unsafe하다)' 라고 표현합니다.
그럼 Thread safe 하게 구현하려면 어떻게 해야 할까요?
3. synchronized
가장 간단한 방법은 Thread safe 하길 원하는 변수나 메소드에 synchronized 키워드를 붙이는 것 입니다.
public class ThreadSafeTest {
public static synchronized int testNum = 10;
public static synchronized int getTestPlusNum(int plusNum) {
testNum += plusNum;
return testNum;
}
}
이렇게 syncronized 키워드를 붙이게 되면 하나의 Thread에서 변수나 메소드에 접근하게 되면 해당 변수, 메소드가 Lock이 걸려 하나의 Thread에서만 접근이 가능하게 됩니다. 그리고 위의 코드는 아래의 코드와 동일합니다.
public class ThreadSafeTest {
public static synchronized int testNum = 10;
public static int getTestPlusNum(int plusNum) {
syncronized(ThreadSafeTest.class){
testNum += plusNum;
return testNum;
}
}
}
syncronized 키워드의 사용은 가장 간단한 방법이긴 하지만, 위에서 말씀드린데로, 메소드에 하나의 Thread가 접근하는 경우 Lock이 걸리기 때문에 시간이 오래 걸리는 메소드의 경우 상당한 퍼포먼스의 하락을 가져올 수 있습니다.
이는 singleton 패턴으로 생성된 객체나 spring bean을 활용할 때도 주의해야 될 것 입니다.
4.참고 Thread safe 하지 않은 SimpleDateFormat
Date 형 변환에 사용되는 SimpleDateFormat class 는 Thread safe 하지 않습니다.
그래서 static 으로 SimpleDateFormat 을 사용하는 경우 Multi Thread 환경에서는 주의 해야 합니다.
public static final SimpleDateForamt DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");
public static final testClzz() {
.
.
.
DATE_FORMAT.parse(strDate); // Thread safe 하지 않음!
//new SimpleDateFormat("yyyyMMddHHmmss").parse(strDate); // Thread safe 함
//DateTimeFormatter.ofPattern("yyyyMMddHHmmss", Locale.KOREA); // LocalDateTime을 return
}
그래서 SimpleDateForamt 사용 시 아래와 같이 새로운 Instance를 생성하거나 DateTimeFormatter 와 같이 Thread safe한 클래스의 메소드를 활용해야 합니다.
SimpleDateFormat 보다는 Java8 이후에 나온 DateTimeFormatter를 사용하고, Date 보다는 LocalDate 혹은 LocalDateTime을 활용하도록 합시다.