[java] 언제 그리고 어떻게 ThreadLocal 변수를 사용해야합니까?

언제 ThreadLocal변수를 사용해야 합니까?

어떻게 사용 되나요?



답변

스레드에 안전하지 않은 객체가 있지만 해당 객체에 대한 액세스를 동기화 하지 않으려는 경우 (일반적으로) 사용할 수 있습니다 ( SimpleDateFormat ). 대신 각 스레드에 고유 한 개체 인스턴스를 제공하십시오.

예를 들면 다음과 같습니다.

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}

문서 .


답변

a ThreadLocal는 지정된 내의 데이터에 대한 참조 이므로 스레드 풀을 사용하는 응용 프로그램 서버에서 s를 Thread사용할 때 클래스 로딩 누수가 발생할 수 ThreadLocal있습니다. 당신은 어떤 청소에 대해 매우 신중해야 ThreadLocal당신을들 get()또는 set()사용하여 ThreadLocalremove()방법을.

완료 할 때 정리하지 않으면 배포 된 웹앱의 일부로로드 된 클래스에 대한 참조는 영구 힙에 유지되며 가비지 수집을받지 않습니다. webapp을 재배포 / 배포 해제하면 webapp이 소유 한 것이 아니기 Thread때문에 webapp의 클래스에 대한 각 참조를 정리 Thread하지 않습니다. 각 연속 배포는 가비지 수집되지 않는 클래스의 새 인스턴스를 만듭니다.

java.lang.OutOfMemoryError: PermGen space일부 인터넷 검색 으로 인해 -XX:MaxPermSize버그가 수정되지 않고 메모리 부족 예외가 발생할 수 있습니다.

이러한 문제점이 발생하면 Eclipse의 메모리 분석기 를 사용 하거나 Frank Kieviet의 안내서후속 조치를 통해 이러한 참조를 보유하는 스레드 및 클래스를 판별 할 수 있습니다 .

업데이트 : Alex Vasseur의 블로그 항목 을 다시 발견 하여 ThreadLocal내가 겪고 있는 문제를 추적하는 데 도움 이되었습니다.


답변

많은 프레임 워크는 ThreadLocals를 사용하여 현재 스레드와 관련된 일부 컨텍스트를 유지합니다. 예를 들어, 현재 트랜잭션이 ThreadLocal에 저장 될 때 스택을 다운받는 누군가가 액세스해야 할 경우를 대비하여 모든 메소드 호출을 통해 매개 변수로 전달할 필요는 없습니다. 웹 응용 프로그램은 현재 요청 및 세션에 대한 정보를 ThreadLocal에 저장하여 응용 프로그램이 쉽게 액세스 할 수 있도록합니다. Guice를 사용 하면 주입 된 객체에 대한 사용자 지정 범위 를 구현할 때 ThreadLocals를 사용할 수 있습니다 (Guice의 기본 서블릿 범위는 대부분 사용합니다).

ThreadLocals는 일종의 전역 변수 (하나의 스레드로 제한되기 때문에 약간 덜 악하지만), 원하지 않는 부작용과 메모리 누수를 피하기 위해 사용할 때주의해야합니다. ThreadLocal 값이 더 이상 필요하지 않을 때 항상 자동으로 지워지고 API를 잘못 사용할 수 없도록 API를 설계하십시오 (예 : ). ThreadLocals를 사용하여 코드를 더 깨끗하게 만들 수 있으며, 드물게 작동하는 유일한 방법입니다. 현재 프로젝트에는 두 가지 경우가 있습니다. 여기 에는 “정적 필드 및 전역 변수”에 설명되어 있습니다.


답변

Java에서 스레드마다 다를 수있는 데이텀이있는 경우 해당 데이텀을 필요한 (또는 필요할 수있는) 모든 메소드로 전달하거나 데이텀을 스레드와 연관시키는 선택이 있습니다. 모든 방법이 이미 공통 “컨텍스트”변수를 통과해야하는 경우 모든 곳에서 데이텀을 전달하는 것이 가능할 수 있습니다.

그렇지 않은 경우 추가 매개 변수로 메소드 서명을 어지럽히 지 않을 수 있습니다. 스레드되지 않은 세계에서는 전역 변수에 해당하는 Java 문제를 해결할 수 있습니다. 스레드 단어에서 전역 변수에 해당하는 것은 스레드 로컬 변수입니다.


답변

Java Concurrency in Practice 책에는 좋은 예가 있습니다. 저자 ( Joshua Bloch )는 스레드 제한이 스레드 안전성을 달성하는 가장 간단한 방법 중 하나 인 방법을 설명하고 ThreadLocal 은 스레드 제한을 유지하는보다 공식적인 방법입니다. 결국 그는 사람들이 그것을 글로벌 변수로 사용하여 어떻게 남용 할 수 있는지 설명합니다.

언급 한 책에서 텍스트를 복사했지만 ThreadLocal을 사용해야하는 곳을 이해하는 것이별로 중요하지 않으므로 코드 3.10이 누락되었습니다.

스레드 로컬 변수는 종종 가변 단일 톤 또는 전역 변수를 기반으로하는 설계에서 공유를 방지하는 데 사용됩니다. 예를 들어 단일 스레드 응용 프로그램은 시작시 초기화되는 전역 데이터베이스 연결을 유지하여 모든 메서드에 Connection을 전달하지 않아도됩니다. JDBC 연결은 스레드로부터 안전하지 않을 수 있으므로 추가 조정없이 전역 연결을 사용하는 다중 스레드 응용 프로그램도 스레드로부터 안전하지 않습니다. Listing 3.10의 ConnectionHolder에서와 같이 ThreadLocal을 사용하여 JDBC 연결을 저장하면 각 스레드는 자체 연결을 갖게된다.

ThreadLocal은 응용 프로그램 프레임 워크 구현에 널리 사용됩니다. 예를 들어, J2EE 컨테이너는 EJB 호출 기간 동안 트랜잭션 컨텍스트를 실행 스레드와 연관시킵니다. 이것은 트랜잭션 컨텍스트를 보유하는 정적 Thread-Local을 사용하여 쉽게 구현됩니다. 프레임 워크 코드는 현재 실행중인 트랜잭션을 결정해야 할 때이 ThreadLocal에서 트랜잭션 컨텍스트를 가져옵니다. 이는 실행 컨텍스트 정보를 모든 메소드에 전달할 필요가 줄어들지 만이 메커니즘을 사용하는 모든 코드를 프레임 워크에 결합한다는 점에서 편리합니다.

스레드 제한 속성을 전역 변수 사용 라이센스로 처리하거나 “숨겨진”메서드 인수를 만드는 수단으로 ThreadLocal을 악용하기 쉽습니다. 전역 변수와 마찬가지로 스레드 지역 변수는 재사용 성을 떨어 뜨리고 클래스간에 숨겨진 커플 링을 유발할 수 있으므로주의해서 사용해야합니다.


답변

기본적으로, 당신은 필요로 할 때 , 현재의 thread에 의존 변수의 값을 하고 당신이 다른 방법으로 스레드에 가치를 부여하는 편리하지 않습니다 (스레드를 서브 클래스, 예를 들어).

일반적인 경우는 다른 프레임 워크가 스레드를 생성 한 경우입니다. 코드가 실행중인 예 : 서블릿 컨테이너)를 생성 한 경우 또는 변수가 “논리적 위치”(변수가 아닌) “논리적 위치”에 있기 때문에 ThreadLocal을 사용하는 것이 더 의미가있는 경우입니다. Thread 서브 클래스 또는 다른 해시 맵에 매달려 있습니다).

내 웹 사이트에서 ThreadLocal언제 사용 해야하는지에 대한 추가 토론과 예가 있습니다.

어떤 사람들은 스레드 번호가 필요한 특정 동시 알고리즘에서 각 스레드에 “스레드 ID”를 연결하는 방법으로 ThreadLocal을 사용하도록 권장합니다 (예 : Herlihy & Shavit 참조). 그러한 경우, 실제로 혜택을 받고 있는지 확인하십시오!


답변

  1. Java의 ThreadLocal은 JDK 1.2에 도입되었지만 나중에 JDK 1.5에서 생성되어 ThreadLocal 변수에 유형 안전성을 도입했습니다.

  2. ThreadLocal은 Thread 범위와 연관 될 수 있습니다. Thread에 의해 실행되는 모든 코드는 ThreadLocal 변수에 액세스 할 수 있지만 두 개의 스레드는 서로 스레드 ThreadLocal 변수를 볼 수 없습니다.

  3. 각 스레드에는 ThreadLocal 변수의 독점 사본이 있습니다. 스레드 로컬 변수에는 스레드가 완료되거나 종료 된 후 (일반적으로 또는 예외로 인해) 가비지 콜렉션에 적합하게됩니다. ThreadLocal 변수에는 다른 라이브 참조가 없습니다.

  4. Java의 ThreadLocal 변수는 일반적으로 클래스의 전용 정적 필드이며 Thread 내에서 상태를 유지합니다.

더 읽기 : Java의 ThreadLocal-예제 프로그램 및 학습서