티스토리 뷰

반응형

Thread 가시성이란 ? 

Thread 가시성이란 Thread의 시야 범위를 뜻한다. 공유하는 변수에 연산이 일어날 때 CPU를 점유하고 동작하는데 이 때 main memory에만 존재하는 것이 아니라 CPU cache에도 공유하는 자원에 대한 데이터가 들어있다. 이 때 CPU cache를 읽어오는데 언제 main memory에 옮겨갈 지 모르기 때문에 여러 thread가 동시에 읽음 연산과 쓰기 연산을 한다면 main memory에서 cache로 데이터를 옮기는 과정에서 다른 thread가 연산을 진행하여 결국 데이터 불일치 문제가 생기는 것이다.

 

이런 불일치 문제를 Thread 가시성 이슈라고 하며 자바에서는 volatile 키워드를 통해 해결할 수 있다. volatile은 캐시가 아닌 main memory에서 데이터를 읽어오기 때문에 가시성 문제를 해결할 수 있다.

만약 연산에는 문제가 없지만 특정 데이터를 읽어올 때 제대로 읽어오지 못하여 오류가 난다면 가시성 문제를 고려해 보아야한다.

public class BoardCountViewTest {

    private boolean turn = true;
    private int viewCount = 0;
    private final int TEST_REPETITION = 1000;

    @Test
    public void Test_AtomicIssue() {
        ExecutorService es = Executors.newFixedThreadPool(2);

        es.execute(new GetViewCount());
        es.execute(new IncreaseView());

        es.shutdown();

        try {
            es.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("viewCount >>> " + viewCount);
    }

    class IncreaseView implements Runnable {
        @Override
        public void run() {
            while(true) {
                if (BoardCountViewTest.this.turn) {
                    BoardCountViewTest.this.viewCount ++;
                    BoardCountViewTest.this.turn = false;
                }
                if ( BoardCountViewTest.this.viewCount == TEST_REPETITION) {
                    break;
                }
            }
        }
    }

    class GetViewCount implements Runnable {
        @Override
        public void run() {
            while (true){
                if (!BoardCountViewTest.this.turn) {
                    System.out.println("view_count : " + BoardCountViewTest.this.viewCount);
                    BoardCountViewTest.this.turn = true;
                }
                if (BoardCountViewTest.this.viewCount == TEST_REPETITION) {
                    break;
                }
            }
        }
    }
}

위 코드를 실행 시켜보면 아마 굉장히 오래 동안 실행될 것이다. 이유는 done이라는 boolean 변수를 스레드가 제대로 읽어오지 못하기 때문에 count를 제대로 연산하지도 않고 읽어오지도 못해서 while문을 빠져나오지 못한다.

volatile 키워드를 넣어주면 정상적으로 돌아갈 것이다.

 

원자성이란?

Syncronized는 특정 연산을 하는 과정에서 연산을 하는 스레드 외에 모든 스레드에 lock을 걸기 때문에 작업을 할 수 없게 된다. 또한 Thread를 blocked 상태에서 ready queue로 보내고 run을 하는 단계까지가 필요하다. AtomicValue는 CAS 알고리즘을 이용하여 non-blocking 하면서 원자성을 보장하여 동시성을 제어한다. 

 

https://golf-dev.tistory.com/25

 

<자바 고급스터디 6주차> 자바의 동시성 이슈

자바는 동시성 문제를 위해 4가지 해결책을 갖고 있다. Syncronized 키워드 Concurrency 라이브러리 Atomic volatile 우리는 그 해결책인 4가지 키워드를 잡고 학습해볼 것이다. Synchronized 자바는 mult-thread 를

golf-dev.tistory.com

자바에서는 해결하는 이유를 잘 정리해놓았으니 참고바란다.

 

여기서는 CAS 알고리즘에 대해서 알아보도록하자

  • 인자로 기존 값과 변경할 값을 전달한다. 
  • 기존 값이 현재 메모리가 가지고 있는 값과 같다면 변경할 값을 반영하며 true를 반환한다.
  • 반대로 기존 값이 현재 메모리가 가지고 있는 값과 다르다면 값을 반영하지 않고 false를 반환한다. 

이 때 위에서 언급한 가시성 개념이 등장하는데 기존 값은 공유된 자원을 갖고 연산을 하고 메모리가 가지고 있는 값과 비교하게 되는데 이 때 메모리가 아닌 cache를 읽어온다면 잘못된 데이터를 읽어올 수 있다. 그래서 Java에서는 volatile을 이용하여 메모리를 읽어오게 하여 더 정확한 연산을 하게한다. 

실제로 AtomicInteger는 volatile 키워드를 value에 달고 있다.

 

Reference.

https://steady-coding.tistory.com/568

 

[Java] atomic과 CAS 알고리즘

java-study에서 스터디를 진행하고 있습니다. synchronized의 문제점 synchronized는 blocking을사용하여 멀티 스레드 환경에서 공유 객체를 동기화하는 키워드이다. 그러나 blocking에는 여러 가지 단점이 존

steady-coding.tistory.com

'CS > OS' 카테고리의 다른 글

[Thread chapter.02] Thread Concurrency & Parallel Programming  (0) 2022.11.21
[Thread chapter.01] Thread에 대해서  (0) 2022.11.20
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함