자바 다 중 스 레 드(6),ThreadLocal 클래스


개술
 
ThreadLocal 이 뭐 죠?사실 ThreadLocal 은 스 레 드 의 로 컬 구현 버 전이 아니 라 Thread 가 아니 라 threadlocalbayer(스 레 드 부분 변수)입 니 다.아마도 그것 을 ThreadLocalVar 라 고 명명 하 는 것 이 더 적합 할 것 이다.스 레 드 부분 변수(ThreadLocal)의 실제 기능 은 매우 간단 합 니 다.이 변 수 를 사용 하 는 모든 스 레 드 에 변수 값 의 사본 을 제공 하 는 것 입 니 다.자바 에서 비교적 특수 한 스 레 드 바 인 딩 체제 로 모든 스 레 드 가 자신의 사본 을 독립 적 으로 바 꿀 수 있 으 며 다른 스 레 드 의 사본 과 충돌 하지 않 습 니 다.
 
스 레 드 의 측면 에서 볼 때 모든 스 레 드 는 스 레 드 부분 변수 사본 에 대한 암시 적 인 인용 을 유지 합 니 다.스 레 드 가 활동 적 이 고 ThreadLocal 인 스 턴 스 가 접근 할 수 있 습 니 다.스 레 드 가 사라 진 후에 스 레 드 부분 인 스 턴 스 의 모든 복사 본 은 쓰레기 로 회수 된다(이 복사 본 에 대한 다른 참조 가 존재 하지 않 는 한).
 
ThreadLocal 을 통 해 액세스 하 는 데 이 터 는 항상 현재 스 레 드 와 관련 이 있 습 니 다.즉,JVM 은 모든 실행 스 레 드 에 개인 적 인 로 컬 인 스 턴 스 액세스 공간 을 연결 하여 다 중 스 레 드 환경 에서 자주 발생 하 는 동시 방문 문제 에 격 리 체 제 를 제공 합 니 다.
 
ThreadLocal 은 어떻게 모든 스 레 드 유지 변 수 를 위 한 복사 본 을 만 듭 니까?사실 실현 하 는 사고방식 은 매우 간단 하 다.ThreadLocal 클래스 에 맵 이 하나 있 는데 모든 라인 의 변 수 를 저장 하 는 복사 본 에 사용 된다.
 
요약 하면 다 중 스 레 드 자원 공유 문제 에 대해 동기 화 체 제 는'시간 으로 공간 을 바꾼다'는 방식 을 사 용 했 고 ThreadLocal 은'공간 으로 시간 을 바꾼다'는 방식 을 사용 했다.전 자 는 하나의 변 수 를 제공 하여 서로 다른 스 레 드 를 줄 지어 방문 하 게 하고 후 자 는 모든 스 레 드 에 변 수 를 제공 하기 때문에 서로 영향 을 주지 않 고 동시에 방문 할 수 있다.
 
2.API 설명
 
ThreadLocal()
          스 레 드 로 컬 변 수 를 만 듭 니 다.
 
T get()
          이 스 레 드 부분 변수의 현재 스 레 드 던 전의 값 을 되 돌려 줍 니 다.스 레 드 가 처음으로 이 방법 을 호출 하면 이 던 전 을 만 들 고 초기 화 합 니 다.
 
protected  T initialValue()
          이 스 레 드 부분 변수의 현재 스 레 드 의 초기 값 을 되 돌려 줍 니 다.스 레 드 에 접근 할 때마다 모든 스 레 드 부분 변 수 를 얻 을 때 이 방법 을 한 번 호출 합 니 다.즉,스 레 드 가 처음으로 get()방법 으로 변 수 를 방문 할 때 입 니 다.스 레 드 가 get 방법 보다 set(T)방법 을 먼저 호출 하면 스 레 드 에서 initialValue 방법 을 다시 호출 하지 않 습 니 다.
 
   이 를 실현 하려 면 null 만 되 돌려 줍 니 다.프로그래머 가 스 레 드 부분 변 수 를 null 이외 의 값 으로 초기 화 하려 면 ThreadLocal 에 하위 클래스 를 만 들 고 이 방법 을 다시 써 야 합 니 다.보통 익명 내부 클래스 를 사용한다.initial Value 의 전형 적 인 실현 은 적당 한 구조 방법 을 호출 하고 새로운 구조의 대상 으로 돌아 갈 것 이다.
 
void remove()
          이 스 레 드 부분 변수의 값 을 제거 합 니 다.이것 은 스 레 드 부분 변수의 저장 수 요 를 줄 이 는 데 도움 이 될 수 있다.이 스 레 드 부분 변 수 를 다시 방문 하면 기본 값 으로 initial Value 를 가 집 니 다.
 
void set(T value)
          이 스 레 드 부분 변수의 현재 스 레 드 던 전의 값 을 지정 값 으로 설정 합 니 다.많은 프로그램 들 이 이 기능 을 필요 로 하지 않 습 니 다.이 기능 들 은 initialValue()방법 에 만 의존 하여 스 레 드 부분 변수의 값 을 설정 합 니 다.
 
프로그램 에 서 는 일반적으로 initialValue 방법 을 다시 써 서 특정한 초기 값 을 지정 합 니 다.
 
 
3.전형 적 인 사례
 
1.Hiberante 의 Session 도구 류 Hibernateutil
이 클래스 는 Hibernate 공식 문서 의 Hibernateutil 클래스 로 session 관리 에 사 용 됩 니 다.
 
public class HibernateUtil {
    private static Log log = LogFactory.getLog(HibernateUtil.class);
    private static final SessionFactory sessionFactory;     //  SessionFactory
 
    static {
        try {
            //         hibernate.cfg.xml  SessionFactory
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            log.error("   SessionFactory  !", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    //        session,    Hibernate Session
    public static final ThreadLocal session = new ThreadLocal();
 
    /**
     *         Session
     * @return Session
     * @throws HibernateException
     */
    public static Session currentSession() throws HibernateException {
        Session s = (Session) session.get();
        //   Session     ,     Session
        if (s == null) {
            s = sessionFactory.openSession();
            session.set(s);         //    Session          
        }
        return s;
    }
 
    public static void closeSession() throws HibernateException {
        //        ,      Session  
        Session s = (Session) session.get();
        session.set(null);
        if (s != null)
            s.close();
    }
}

 
이 클래스 에서 ThreadLocal 의 initialValue()방법 을 다시 쓰 지 않 았 기 때문에 스 레 드 부분 변수 session 의 초기 값 은 null 이 고,currentSession()을 처음 호출 할 때 스 레 드 부분 변수의 get()방법 도 null 입 니 다.따라서 session 에 대해 판단 을 했 습 니 다.null 이면 세 션 을 새로 열 고 스 레 드 부분 변수 session 에 저장 하 는 것 이 매우 관건 입 니 다.이것 은'Public static final ThreadLocal session=new ThreadLocal()'이 만 든 대상 session 이 Hibernate Session 대상 으로 강제 전환 할 수 있 는 이유 입 니 다.
 
2.다른 인 스 턴 스
빈 을 만 들 고 서로 다른 스 레 드 대상 을 통 해 빈 속성 을 설정 하여 각 스 레 드 빈 대상 의 독립 성 을 확보 합 니 다.
 
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-11-23
 * Time: 10:45:02
 *   
 */
public class Student {
    private int age = 0;   //  
 
    public int getAge() {
        return this.age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}
 
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-11-23
 * Time: 10:53:33
 *         
 */
public class ThreadLocalDemo implements Runnable {
    //        studentLocal,           Student  
    private final static ThreadLocal studentLocal = new ThreadLocal();
 
    public static void main(String[] agrs) {
        ThreadLocalDemo td = new ThreadLocalDemo();
        Thread t1 = new Thread(td, "a");
        Thread t2 = new Thread(td, "b");
        t1.start();
        t2.start();
    }
 
    public void run() {
        accessStudent();
    }
 
    /**
     *       ,    
     */
    public void accessStudent() {
        //         
        String currentThreadName = Thread.currentThread().getName();
        System.out.println(currentThreadName + " is running!");
        //          
        Random random = new Random();
        int age = random.nextInt(100);
        System.out.println("thread " + currentThreadName + " set age to:" + age);
        //    Student  ,               
        Student student = getStudent();
        student.setAge(age);
        System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());
        try {
            Thread.sleep(500);
        }
        catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge());
    }
 
    protected Student getStudent() {
        //              Student  
        Student student = (Student) studentLocal.get();
        //            ,studentLocal.get()   null
        if (student == null) {
            //    Student  ,          studentLocal 
            student = new Student();
            studentLocal.set(student);
        }
        return student;
    }
}
 
    :
a is running!
thread a set age to:76
b is running!
thread b set age to:27
thread a first read age is:76
thread b first read age is:27
thread a second read age is:76
thread b second read age is:27
 

a,b 두 스 레 드 age 가 서로 다른 시간 에 인쇄 한 값 이 똑 같은 것 을 볼 수 있 습 니 다.이 프로그램 은 ThreadLocal 을 통 해 다 중 스 레 드 병행 을 실현 할 뿐만 아니 라 데이터 의 안전성 도 고려 합 니 다.
 
총화
 
ThreadLocal 사용 장 소 는 주로 다 중 스 레 드 에서 데이터 데이터 데이터 가 병발 로 인해 일치 하지 않 는 문 제 를 해결 합 니 다.ThreadLocal 은 모든 스 레 드 의 동시 방문 데이터 에 복사 본 을 제공 하고 복사 본 을 방문 하여 업 무 를 수행 합 니 다.이러한 결 과 는 메모리 가 소모 되 었 고 스 레 드 동기 화가 가 져 온 성능 소 모 를 크게 줄 였 으 며 스 레 드 병행 제어 의 복잡 도 를 줄 였 습 니 다.
 
ThreadLocal 은 원자 형식 을 사용 할 수 없고 Object 형식 만 사용 할 수 있 습 니 다.ThreadLocal 의 사용 은 synchronized 보다 훨씬 간단 합 니 다.
 
ThreadLocal 과 Synchonized 는 다 중 스 레 드 병행 접근 을 해결 하 는 데 사 용 됩 니 다.그러나 ThreadLocal 과 synchronized 는 본질 적 인 차이 가 있다.synchronized 는 잠 금 체 제 를 이용 하여 변수 나 코드 블록 을 한 스 레 드 에 만 접근 할 수 있 도록 합 니 다.한편,ThreadLocal 은 모든 스 레 드 에 변수의 복사 본 을 제공 하여 모든 스 레 드 가 특정한 시간 에 같은 대상 이 아니 라 여러 스 레 드 가 데이터 에 대한 데이터 공 유 를 격 리 시 켰 다.반면 Synchronized 는 반대로 여러 스 레 드 간 통신 시 데이터 공 유 를 얻 을 수 있 습 니 다.
 
Synchronized 는 스 레 드 간 데이터 공유 에 사용 되 고 ThreadLocal 은 스 레 드 간 데이터 격 리 에 사 용 됩 니 다.
 
물론 ThreadLocal 은 synchronized 를 대체 할 수 없습니다.서로 다른 문제 영역 을 처리 합 니 다.Synchronized 는 동기 화 메커니즘 을 실현 하 는 데 사용 되 며 ThreadLocal 보다 더 복잡 합 니 다.
 
 
5.ThreadLocal 에서 사용 하 는 일반적인 절차
 
1.다 중 스 레 드 클래스(예 를 들 어 ThreadDemo 클래스)에서 ThreadLocal 대상 threadXxx 를 만 들 고 스 레 드 간 격 리 처리 대상 xxx 를 저장 합 니 다.
2.ThreadDemo 클래스 에서 격 리 접근 할 데 이 터 를 가 져 오 는 방법 getXxx()를 만 듭 니 다.방법 에서 판단 하면 ThreadLocal 대상 이 null 일 때 new()격 리 접근 형식의 대상 을 만 들 고 응용 할 형식 으로 강제로 전환 해 야 합 니 다.
3.ThreadDemo 류 의 run()방법 에서 getXxx()방법 으로 조작 할 데 이 터 를 얻 으 면 모든 스 레 드 가 하나의 데이터 대상 에 대응 하고 언제든지 이 대상 을 조작 할 수 있 습 니 다.
이상 은 네트워크 에서 원본 코드 를 본 후에 자신의 이 해 를 보 았 습 니 다.ThreadLocal 은'스 레 드 의 로 컬 변수'라 고 부 르 는 것 이 가장 적합 합 니 다.이 복사 본 은 실제 적 으로 현재 스 레 드 인 스 턴 스 의 threadLocals 변수 에 저 장 됩 니 다.즉,t.threadLocals 입 니 다.이 threadLocals 변 수 는 실제 적 으로 ThreadLocal 의 내부 클래스 인 ThreadLocal.ThreadLocalMap 의 인 스 턴 스 입 니 다.ThreadLocalMap 은 실제 맵 입 니 다.현재 ThreadLcoal 인 스 턴 스 를 key 로 저장 합 니 다.

좋은 웹페이지 즐겨찾기