본문 바로가기

Language/Java

JAVA ThreadLocal

JAVA ThreadLocal란?


각각의 Thread에서만 사용되는 전역 변수를 만들어 주는 개념이다. 때문에 각각의 Thread마다 다른 값을 사용 할 수 있다.

스레드에서 변수가 임의로 공유되는 상황을 막기 위해서 자주 사용이 된다.


-private static으로 선언

-set과 get메소드로 사용됨

-싱글턴 구현, 프로임워크의 환경변수 공유등에 많이 사용.

 ThreadLocal 은 전역변수는 아니지만 전역 변수처럼 동작하기 때문에 코드의 재사용성을 떨어트리고 부작용을 유발할 수 있다.


<설명1>



스레드 내보의 값과 값을 가지고 있는 객체를 연결해 스레드 한정 기법을 적용할수 있도록 도와주는 형식적인 방법으로 ThreadLocal이 있다.

이 ThreadLocal은 호출하는 스레드마다 다른 값을 사용할 수 있도록 관리해준다.

즉, ThreadLocal의 get 메소드를 호출하면 현재 실행 중인 스레드에서 최근에 set 메소드로 저장했던 값을 가지고 온다. 


이러한 ThreadLocal은 여러 스레드에서 변수가 임의로 공유되는 상황을 막기 위해서 자주 사용이 된다.


예를 들어 데이터베이스에 접속할 때 매번 Connection 인스턴스를 생성하는 부담을 줄이고자, 시작 시점에 Connection 인스턴스를 전역 변수에 넣어두고 계속해서 사용하는 방법을 사용하기도 한다. 하지만 JDBC 연결은 스레드에 안전하지 않기 때문에 적절한 동기화 없이 사용할 수 없다.


다음은 이러한 상황에서 ThreadLocal을 이용해서 해결한 예이다.


private static ThreadLocal<Connection> connectionHolder

= new ThreadLocal<Connection>() {

public Connection initialValue() {

return DriverManager.getConnection(DB_URL);

}

};

public static Connection getConnection() {

return connectionHolder.get();

}


개념적으로 본다면, ThreadLocal<T> 클래스는 Map<Thread, T>라는 자료 구조로 구성되어 있다고 생각할 수 있다. 하지만, 실제로 이렇게 구성된 것은 아니다. 결과적으로 ThreadLocal은 스레드 안전성을 보장할 수 있다.


ThreadLocal을 사용하면 하나의 스레드에서 동일한 값을 공유하면서, 스레드 한정을 유지할 수 있어서 편리하지만, 이것을 사용하는 코드는 해당 프레임웍에 대한 의존성을 갖게 된다. ThreadLocal 은 전역변수는 아니지만 전역 변수처럼 동작하기 때문에 코드의 재사용성을 떨어트리고 SideEffect를 유발할 수 있다.

[출처] ThreadLocal|작성자 appchemist




<설명2>








<설명3>



프로젝트에서 쓸려고 ThreadLocal 에대해서 좀 연구를 해보았습니다.
ThreadLocal 은 기존에 잘 안써보신 분도 많을 듯 하여, 친절하게 그림으로 설명합니다. ^__^



Java 에서 ThreadLocal 은 현재 수행되고 있는 각각의 Thread 상에서 고유한 저장소를 제공해 주는 클래스로
싱글턴 구현이나 프레임웍에서 환경변수 공유등등에 유용하게 사용될수있다. 
지루한 설명 보다는 실제 첫번째 코드를 읽어 보고 수행해 보자. 수행 흐름은 다음과 같다.

 

 

수행결과로 매번 ThreadLocal 을 하는것은 해당 스레드 내에서, ThreadLocal Reference 가 달라지기 때문에  마지막 NEW_ThreadLocal변수 값을  할당한 ThreadLocal Reference 와 ThreadLocal변수, testObj 값을 할당한 ThreadLocal Reference 는 서로 다른 것을 알 수 있다.

 

 

두번째 소스는 실제 프레임웍에서 동작하는 것과 비슷하게 Tier 별로 나누어 구성하였다. 모두 3 개의 Thread 가 각기 동작 하며 CMD 와 Control Tier 를 거쳐 모의 수행된다. 
CMD Tier 에서는 자신의 ThreadLocal 변수에 CMD_ThreadLocal  값을 할당하고 Control Tier 에서는 설정된 값을 할당하지 않고 가져오기만 한다.

 

 

수행 결과에서 확인 할수 있듯이 ThreadLocal 은 Tier 별로 유지되지는 않는다. 같은 CMD 클래스 내에서는 할당한 CMD_ThreadLocal  값을 가져왔지만, Control Tier 에서는 설정되지 않아 null 값을 가져왔다. 
실제 ThreadLocal  Reference 를 찍어 보면 그 이유를 알수있다. 서로 ThreadLocal Reference  가 다르기 때문에 값이 보존되지 않는 것이다.

 


실제 Java ThreadLocal 은 내부적으로 ThreadLocalMap 이라는 hashMap 형태의 자료구조를 가지고 있다. 물론 key 와 value 로 구성되어 있으며, key 는 자신의 reference 인 this 가 되고 , value 는 설정한 Object 가 된다. 
결과적으로 두번째 예제에서 Control Tier 의 결과 값이 null 인 것은 자신의 reference 인 this 가 다르기 때문에 해당 key 에 대해 설정된 값이 없으므로 null 이기 반환 되기 때문이다.

 


 

세번째 소스는 두번째 소스에 GlobalThreadLocal 구현을 첨부 하였다.  단순히 new ThreadLocal() 을 하는 것이 아니라 GlobalThreadLocal 클래스를 통해 ThreadLocal reference 를 유지 할수 있도록 해준다. 
ThreadLocal reference 유지하기 위한 방법으로 ThreadLocal reference 를 static 변수로 만드는 방법을 사용하였다.

 

 

수행 결과에서는 Tier 간에 출력된 ThreadLocal  reference 가 동일 하기 때문에 null 이 아니라 원하는 스레드간-전역변수가 출력되었다.

 


네번째 예제에서는 GlobalThreadLocal 가  Object 만을 주고 받는것에 기능을 추가하여 내부적으로 , key 와 value 쌍을 갖는 HashMap 을 갖도록 구성해 보았다.
ThreadLocal  reference 을 유지 하기 위해 static 으로 선언하는 것은 동일 하다.

 

 

모두 1000 개의 Thread 를 통한 수행결과에서는  각각의 Thread 마다 고유한 쓰레드간-전역변수의 효과가 나타났음을 확인할 수 있다.

 


 

'Language > Java' 카테고리의 다른 글

JAVA 접근 제한자 (public, private, protected, default)  (1) 2014.02.27
Java Reflection 개념 및 사용법  (4) 2014.02.27
Java Code Convention  (0) 2014.02.24
PreparedStatement batch insert (JDBC)  (0) 2014.02.21
Spring Remote (RMI) 예제  (0) 2014.02.21