동시성 문제해결 ThreadLocal

언젠간·2022년 12월 16일
0

동시성문제

목록 보기
1/1

동시성 문제

  • 동시성 문제는 지역 변수에서는 발생하지 않는다. 지역 변수에서는 쓰레드마다 각자 다른 메모리 영역에 할당되기 때문이다.
  • 단순 조회작업이 아닌, 수정작업이 있을때 동시성 문제가 발생한다.

예제

  • userA가 자신의 Key값을 keyA로 설정하고, userB는 자신의 Key값을 keyB로 설정하려 한다.
      1. userA가 자신의 key값을 keyA로 셋팅
      1. 1초후에 userA의 key = keyA로 출력하려 하지만
      1. 0~1초 사이인 0.1초 후에 userB가 key 값을 keyB로 셋팅해버림
      1. 그 결과 userA와 userB의 key값이 모두 keyB로 셋팅되어버림
	package com.example.controller;

	public class NormalCase {
		private static String key = ""; //전역변수 -> 동시성 문제 발생가능
	
		public static void main(String[] args) throws InterruptedException {
		
          Runnable defaultUserA = () -> {
              try {
                  function("keyA");
              } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
          };

          Runnable defaultUserB = () -> {
              try {
                  function("keyB");
              } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
          };

          System.out.println("NormalCase start");

          Thread threadA = new Thread(defaultUserA);
          threadA.setName("threadA");

          Thread threadB = new Thread(defaultUserB);
          threadA.setName("threadB");

          threadA.start();
          Thread.sleep(100);

          threadB.start(); //3. threadB가 key값을 userB로 셋팅해버림
          Thread.sleep(3000);

          System.out.println("NormalCase End");
      }

      public static void function(String keyName) throws InterruptedException {
          key = keyName; //1. userA가 자신의 key값을 keyA로 셋팅

          Thread.sleep(1000); //2. 1초후에 key = keyA로 출력하려 하지만
          System.out.println(keyName + " 의 key = " + key); //4. userA의 키값이 keyB로 출력됨
      }
}

해결방법 ThreadLocal

  • ThreadLocal이란 Thread 내부에서 사용되는 지역변수이다.
  • 지역변수이므로 공유되지 않는다.
  • 반드시 사용 후에 remove() 해줘야 한다.

예제

  • 위와 동일하게 userA가 자신의 Key값을 keyA로 설정하고, userB는 자신의 Key값을 keyB로 설정하려 한다.
      1. userA가 자신의 key값을 localAkey = keyA로 셋팅
      1. 1초후에 userA의 localAkey = keyA로 출력하려 함
      1. 그 0~1초 사이인 0.1초 후에 userB가 key 값을 localBkey = keyB로 셋팅했지만
      1. userA의 key값은 localAKey에 저장되어 있으므로 정상적으로 출력한다.
      1. userB도 자신의 key값을 localBKey에서 가져오므로 정상 동작한다.
	package com.example.controller;

	public class ThreadLocalCase {
	
      private static ThreadLocal<String> keyDB = new ThreadLocal<>(); //전역변수이지만 지역변수처럼 사용함

      public static void main(String[] args) throws InterruptedException {

          Runnable localUserA = () -> {

              try {
                  function_local("keyA");
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }

          };

          Runnable localUserB = () -> {
              try {
                  function_local("keyB");
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          };

          System.out.println("ThreadLocal Start");

          Thread threadA_Local = new Thread(localUserA);
          threadA_Local.setName("threadA");

          Thread threadB_Local = new Thread(localUserB);
          threadB_Local.setName("threadB");

          threadA_Local.start();
          Thread.sleep(100);
          threadB_Local.start();
          Thread.sleep(3000);

          System.out.println("ThreadLocal End");
      }


      public static void function_local(String keyName) throws InterruptedException {
          keyDB.set(keyName);

          Thread.sleep(1000);
          System.out.println(keyName +" 의 key = " + keyDB.get());
          keyDB.remove();
      }
	
}
 
profile
코딩왕이될사나이

0개의 댓글