[Java] Java의 동시성 문제

Jinjin·2023년 8월 21일
0
post-thumbnail

1. 동시성 이슈?


  • 스레드?
    : cpu 작업의 한단위이다.

  • 멀티스레드 방식?
    : 멀티태스킹을 하는 방식 중, 한 코어에서 여러 스레드를 이용해서 번갈아 작업을 처리하는 방식이다.

  • 멀티스레드의 장점
    : 공유하는 영역이 많아서 프로세스 방식보다 context switching(작업전환) 오버헤드가 작아, 메모리의 리소스가 상대적으로 작다.
    하지만, 자원을 공유해서 단점도 발생한다.

  • 동시성 이슈?
    : 여러 스레드가 동시에 하나의 자원을 공유하고 있기 때문에 같은 자원을 두고 경쟁상태(raceCondition) 같은 문제가 발생한다.


    2. 동시성 vs 병렬성

    ✔ 동시성

    : 동시에 실행되는 것처럼 보이는 것

  • 싱글 코어에서 멀티 스레드를 동작시키기 위한 방식으로, 멀티 태스킹을 위해 여러 개의 스레드가 번갈아가면서 실행되는 성질이다.

  • 멀티 코어에서 멀티 스레드를 이용하여 동시성을 만족할 경우에는 실제 물리적 시간으로 동시에 실행되는 것이다.

    ✔ 병렬성

    : 실제로 동시에 실행되는 것

  • 멀티 코어에서 멀티 스레드를 동작시키는 방식으로, 한 개 이상의 스레드를 포함하는 각 코어들이 동시에 실행되는 성질을 말한다.

    ✔ 스레드 안전성(Thread safe) 이란?

  • 여러 스레드가 작동하는 환경에서도 문제 없이 동작하는 것을 스레드가 안전하다고 한다. 즉, 동시성 이슈를 해결한다면 Thread safe하다고 할 수 있다.


3. 동시성 프로그래밍에서 발생할 수 있는 문제점

[CPU와 RAM의 관계도]

  • RAM에 데이터를 쓰기

    1. CPU가 어떤 작업을 처리하기 위해 데이터가 필요할 때, CPU는 RAM의 일부분을 CPU Cache Memory로 읽는다.
    2. 읽은 데이터로 명령을 수행한다.
    3. RAM에 저장하기 위해서는 CPU Cache Memory에 쓴 다음 RAM에 쓰기 작업을 수행한다.
      📌 하지만 CPU가 캐시에 쓰기 작업을 수행했다고 해서 바로 RAM으로 쓰기 작업을 수행하지 않는다
  • RAM에서 데이터를 읽기

    • 해당 데이터가 RAM에서 변경되었다고 해도, 언제 CPU Cache Memory가 아닌 RAM에서 데이터를 읽어 들여서 CPU Cache Memory를 업데이트할 지 보장하지 않는다.

✔ 동시성 프로그래밍에서는 CPU와 RAM의 중간에 위치하는 CPU Cache Memory와 병렬성이라는 특징 때문에 다수의 스레드가 공유 자원에 접근할 때 두 가지의 문제가 발생할 수 있다.

  • 가시성 문제
  • 원자성(동시 접근)문제

4. 가시성 문제


: 여러 개의 스레드가 사용됨에 따라, CPU Cache Memory와 RAM의 데이터가 서로 일치하지 않아 생기는 문제이다.

  • 해결방법
    - 가시성이 보장되어야 하는 변수를 CPU Cache Memory가 아니라 RAM에서 바로 읽도록 보장해야 한다.
    • 변수에 volatile 키워드를 붙여서 가시성을 보장할 수 있다.

      private static volatile boolean isStop;
    • 가시성이 보장된다고 동시성이 보장되는 것은 아니다.

    • volatile 키워드는 어디까지나 volatile 변수를 메인 메모리로부터 읽을 수 있게 해주는 것이 전부이고, 다른 스레드에 의해 값이 언제든 바뀔 수 있다.

    • 가시성이란 공유 데이터를 읽는 경우의 동시성만 보장하는 것이다.


5. 원자성 문제


1. 원자성과 가시성의 공통점 : 멀티 스레드 환경에서 스레드 사이에 공유 메모리 이슈를 발생한다는 점 => 하지만 두 개념은 다르다.
  • 가시성

    • CPU 와 Cache, Memory 관계 상의 개념
  • 원자성

    • 한 줄의 프로그램 문장이 컴파일러에 의해 기계어로 변경되면서, 이를 기계가 순차적으로 처리하기 위한 여러 개의 Machine Instruction이 만들어져 실행되기 때문에 일어나는 현상
    • Ex) 프로그램 언어적으로 i++; 문장은 다음과 같이 기계가 수행하는 명령어로 쪼개진다.
      • i를 메모리로부터 읽는다.
      • 읽은 값에 1을 더한다.
      • 연산한 값을 메모리에 저장한다.
    • 멀티 스레드 환경에서는 한 스레드가 각 기계 명령어를 수행하는 동안에 다른 스레드가 개입하여 공유 변수에 접근해 같은 기계 명령어를 수행할 수 있으므로 값이 꼬이게 된다.(race Condition)
  • 해결 방법
    1. synchronized
    ✔ synchronized 블럭을 들어가기 전에 CPU Cache Memory와 Main Memory를 동기화 해준다.

    1. atomic
      ✔ CAS 알고리즘에 의해 원자성 문제와 CPU Cache Memory에 잘못된 값을 참조하는 문제를 동시에 해결해준다.
      📌 원자성 문제를 synchronized 또는 atomic을 통해 해결하면 가시성의 문제도 해결된다.


출처 :

https://velog.io/@mooh2jj/%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88
https://steady-coding.tistory.com/554

CODE 예시

동시성을 제어하는 방법

(1) 암시적 Lock(synchronized)

: 동시성을 해결하는 데 가장 간단하면서 쉬운 방법은 Lock을 걸어 버리는 것이다. 즉, 문제가 된 메서드, 변수에 각각 synchronized라는 키워드를 넣어버리는 것이다.

profile
BE Developer

0개의 댓글