☕️ Java/기본

[Java] ThreadLocal에 대해

말 랑 2022. 1. 22. 19:08
728x90

 

프로세스? 쓰레드?

프로세스란 실행 중인 하나의 애플리케이션을 의미하고, 쓰레드란 한 프로세스 내에서 동작하는 여러 실행 흐름을 의미한다.

 

 

여러개의 쓰레드가 동시에 작동하는 것이 멀티 쓰레드이며, 멀티 쓰레드를 사용할 때에는 동기화(Synchronization)교착상태(Deadlock)와 같은 문제들이 발생할 수 있다.

 

 

여러개의 쓰레드가 자원을 공유해서 사용해도 괜찮을 수 있지만, 심각한 오류를 발생시키는 경우가 있다.

이럴 때 쓰레드들이 자원에 동시에 접근하는 것을 막기 위해서 synchronized라는 키워드를 사용해서 쓰레드들의 동기화 문제를 해결할 수 있다.

그러나 synchronized 키워드는 프로그램 성능에 굉장히 악영향을 미친다.

 

 

 


 

 

ThreadLocal

ThreadLocal은 자바의 class이다. 각각의 쓰레드들에게 고유한 저장소를 제공하는 변수라고 생각할 수 있다.

 

두 개(혹은 그 이상)의 쓰레드가 하나의 ThreadLocal 변수를 참조하더라도, 서로 사용하는 ThreadLocal이 달라지는 것이다.

 

즉 멀티 쓰레드 환경에서 각 쓰레드마다 독립적인 변수를 사용할 수 있게 해주는 것이다.

또한 쓰레드가 같다면, 어디서든 참조하여 사용할 수 있게된다.

 

 

 

사용법

ThreadLocal<T> local = new ThreadLocal(); //생성

local.set(T); //값 할당

local.get(); // 값 사용

 

 

 

예시는 다음과 같다.

public class ThreadLocalService {

    private ThreadLocal<String> nameStore = new ThreadLocal<>();

    public String logic(String name){
        System.out.println(String.format("저장 name = %s -> nameStore = %s", name, nameStore.get()));
        nameStore.set(name);
        sleep(1000);
        System.out.println(String.format("조회nameStore = %s", nameStore.get()));
        return nameStore.get();
    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

public class ThreadLocalServiceTest {

    private ThreadLocalService service = new ThreadLocalService();

    @Test
    public void local() throws Exception {
        //given
        Runnable userA = () ->{
            service.logic("userA");
        };

        Runnable userB = () ->{
            service.logic("userB");
        };

        Thread threadA = new Thread(userA);
        threadA.setName("thread-A");
        Thread threadB = new Thread(userB);
        threadB.setName("thread-B");

        threadA.start();

        threadB.start();

        sleep(3000);


    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

만약 ThreadLocal이 아닌 일반 String 필드였다면, 동시성 문제가 발생하여 결과는 다음과 같았을 것이다.

그러나 ThreadLocal을 사용한다면 결과는 다음과 같다.

 

 

주의사항

스레드 로컬은 사용 후 보관된 데이터를 반드시 삭제해 주어야 한다.

그렇지 않다면 재사용 되는 쓰레드가 올바르지 않은 데이터를 참조하여 오류를 발생시킬 수 있다.

 

제거는 다음 메소드를 사용한다.

ThreadLocal.remove()

 

다음과 같이 사용한다.

public class ThreadLocalService {

    private ThreadLocal<String> nameStore = new ThreadLocal<>();

    public String logic(String name){
        try {
            System.out.println(String.format("저장 name = %s -> nameStore = %s", name, nameStore.get()));
            nameStore.set(name);
            sleep(1000);
            System.out.println(String.format("조회nameStore = %s", nameStore.get()));
            return nameStore.get();
        }finally {
            nameStore.remove();
        }

    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

 

 

 

 

 

📔 Reference

 

ThreadLocal 이란 ?

Thread의 장단점 과 ThreadLocal에 대해서

yeonbot.github.io

 

ThreadLocal 사용법과 활용

자바 1.2 버전부터 제공되고 있지만 아직 다수의 개발자들이 잘 몰라서 활용을 잘 못하는 기능이 하나 있는데, 그 기능이 바로 쓰레드 단위로 로컬 변수를 할당하는 기능이다. 이 기능은 ThreadLocal

javacan.tistory.com

 

 

[JAVA] ThreadLocal

ThreadLocal 어제 우아한 형제들 루터회관 14층에서 SLiPP 스터디 중간 세미나가 있었고, 우아한 테크 코스 크루 자격으로 참석할 수 있었다. 첫번째 세션에서 김문수님의 게임 재화 및 재화 로그 시

velog.io

 

728x90