[OS] thread safety

a45hvn·2021년 6월 27일
0

최근 자바에서 stream과 람다식을 이용하면서 코드가 간결해지고 있다. fillter, map, collector 등 어느정도 기능들도 손에 익었고 hash(table,map 등)로 변환하는것을 공부하면서 슬슬 포스팅을 해볼까 계획중이었다.

공부하려고 하자마자 모르는 개념이 모르는 개념으로 설명해주기 시작했다.
HashMap -> concurrrentMap -> thread safety -> atomic -> countDownLatch -> 병렬 처리 ......
overflow 걸리기 전에 적당히 끊고 thread safety먼저 정리하려고 한다.(간단히 읽으면서 배경지식정도만 쌓아두고 다음에 공부하기로 한다... 분명히 어디선가 다시 마주칠 인연이라 생각하니까)

multi-thread 환경에서 하나의 자원을 다양한 thread에서 접근하는 경우가 발생한다. 이런 경우 thread safe하지 않다. 하나의 thread에서는 변경하고 다른 thread에서 조회하는 기능을 하려고 하면 thread의 작동 순서에 따라서 다른 결과가 나올 것이다.

public class ThreadSafe {
   public void test(){
       int loop = 30;
       CountDownLatch countDownLatch = new CountDownLatch(loop);
       ExecutorService executorService = Executors.newFixedThreadPool(10);

       // thread safe 하지 않다
       Map<String, LongAdder> map = new HashMap<>();
       // thread safe 하다
       Map<String,LongAdder> map2 = Collections.synchronizedMap(new HashMap<>());
       Map<String,LongAdder> map3 = new ConcurrentHashMap<>();


       for(int i=0; i<loop; i++){
           int type = i%3;
//            executorService.submit(new Task(String.valueOf(type),countDownLatch,map));
//            executorService.submit(new Task(String.valueOf(type),countDownLatch,map2));
           executorService.submit(new Task(String.valueOf(type),countDownLatch,map3));
       }
       System.out.println(map.toString());
       //{0=9, 1=9, 2=8} 매번 다르게 나온다.
       System.out.println(map2.toString());
       //{0=10, 1=10, 2=10} 항상 같다
       System.out.println(map3.toString());
       //{0=10, 1=10, 2=10} 항상 같다
       executorService.shutdown();
   }

   static class Task implements Runnable{
       private final String taskNo;
       private final CountDownLatch countDownLatch;
       private Map<String,LongAdder> map;

       public Task(String taskNo, CountDownLatch countDownLatch, Map<String, LongAdder> map) {
           this.taskNo = taskNo;
           this.countDownLatch = countDownLatch;
           this.map = map;
       }

       @Override
       public void run() {
           try{
               map.computeIfAbsent(taskNo,s -> new LongAdder()).increment();
           }catch (Exception e) {
               e.printStackTrace();
           }finally {
               countDownLatch.countDown();
           }
       }
   }
}

thread safe에 대해 공부하면서 multi thread환경에서 주의하면서 코딩해야 겠다는 생각이 들었다. stream에 외부 자원을 사용할때 atomic으로 바꾸거나 final로 저장해서 사용하라고 오류가 나왔는데 어떤 맥락인지 알게 되었다. 추후에 병렬 stream에 대해서도 조금 더 알아봐야겠다.


reference 겸 나중에 공부할 내용들...

profile
청포도루이보스민트티

0개의 댓글