prgrms-web-devcourse / BE-Team-preArmand-Book-study

2 stars 2 forks source link

[아이템 62] 코드 62-5 예시 관련(deprecated) #28

Closed epicblues closed 2 years ago

epicblues commented 2 years ago

page 364 코드 62-5에 있는 ThreadLocal 클래스가 java.lang.ThreadLocal과 흡사하다고 한 이유를 잘 모르겠습니다!

코드 62-5와 같은 클래스를 만들어 테스트를 돌려봤습니다.

// 코드 62-5와 같은 코드... 가 아니었음 제가 책을 잘못봐서 뻘질문이 됐습니다... 
public final class CustomThreadLocal<T> {

  private T value;

  public T get() {
    return this.value;
  }

  public void set(T value) {
    this.value = value;
  }
}
 @Test
 @DisplayName("다른 스레드에서 ThreadLocal의 값을 바꿔도 기존 ThreadLocal의 값은 바뀌지 않아야 한다.")
  void threadLocal_test() throws InterruptedException, ExecutionException {
    var threadLocal = new CustomThreadLocal<Integer>();
    threadLocal.set(15);

    // 자바가 제공하는 스레드풀 생성
    ExecutorService executorService = Executors.newFixedThreadPool(1);

    // 다른 스레드가 실행할 작업을 등록한 뒤 실행시킨다.(submit)
    // submit()이 반환한 Future 객체에 get()을 호출하면 둥록한 작업이 완료되어 Integer를 반환할 때까지 메인 스레드는 block된 상태.
    // 사용 이유 : Thread.sleep 보다 확실하게 다른 스레드의 실행을 보장받기 위해?
    Integer differentThreadValue = executorService.submit(() -> {
      threadLocal.set(20);
      return threadLocal.get();
    }).get();

    Integer mainThreadValue = threadLocal.get();
    assertThat(mainThreadValue).isEqualTo(15); // 테스트 실패  expected : 15, but was 20, 즉 메인스레드의 ThreadLocal의 값도 바뀐다.
    assertThat(differentThreadValue).isEqualTo(20);
  }

결과는 원래 스레드에서 설정한 값도 20으로 바뀌기 때문에 테스트를 통과하지 못했습니다. 참고로 java.lang.ThreadLocal로 바꿔서 테스트 했을 때는 통과했습니다.

책에서 현재 스레드 정보를 키 값으로 사용하는 코드를 생략한 걸까요? 아니면 책에서 제가 놓친 것이 있어서 그런지 궁금합니다.

kimziou77 commented 2 years ago

안녕하세요 민성님! 질문에 대한 몇가지 질문이 있어서 왔습니다!! (?) ㅎㅎ

책에 있는 코드들이 조각조각이어서 민성님이 실험하신 코드가 어떻게 구성되어있는지 좀 더 이해하기 좋을것 같습니다.

저의 아주아주 개인적인 의견이지만!! 제가 Callable과 Future, ExecutorServiceUtil가 생소해서 코드를 읽었을때 바로 무엇을 하기 위한건지 알아채기 힘들었던것 같습니다 😿 그래서 이게 제대로 한 실험인지는 모르겠지만... 저는 다음과 같은 방식으로 구현해보았습니다!

    @Test
    void threadLocalTest(){
        var threadLocal = new ThreadLocal<Integer>();

        // thread1 : threadLocal == 15
        threadLocal.set(15);

        new Thread(()->{
            // thread2 : threadLocal == 20
            threadLocal.set(20);
            assertThat(threadLocal.get()).isEqualTo(20);  // validate 
        }).start();

        sleep(1000); // thread2가 threadLocal을 수정 하기전에 밑으로 넘어감 방지

        assertThat(threadLocal.get()).isEqualTo(15); // validate 
    }
epicblues commented 2 years ago

아 말씀하신대로 코드의 가독성이 떨어지는 것 같습니다. 수정을 해서 다시 올리겠습니당 🐢

epicblues commented 2 years ago

아 책(코드 62-5)을 다시 보니까 애초에 ThreadLocal에 대한 구체적인 구현 내용은 없었네요. 제가 책을 잘못 읽어서 생긴 뻘질문 이었습니다. 😥 수치스럽지만 일단 질문 쓴 게 아까워서(?) 일단 박제해놓겠습니다. ㅠㅠ

yuminhwan commented 2 years ago
public class MyThreadLocal<T> {

    public void set(T value) {
        MyThreadLocalMap.threadObjectMap.put(Thread.currentThread(), value);
    }

    @SuppressWarnings("unchecked")
    public T get() {
        return (T) MyThreadLocalMap.threadObjectMap.get(Thread.currentThread());
    }

    static class MyThreadLocalMap {
        static Map<Thread, Object> threadObjectMap = new HashMap<>();
    }

}

요렇게 하면 통과하긴 하네요. 맞게 구현한지는 잘 모르겠네요 😅