동기화와 원자적 연산

이동건 (불꽃냥펀치)·2025년 1월 11일
0

원자적 연산이란?

컴퓨터 과학에서 사용하는 우너자적 연산의 의미는 해당 연산이 더 이상 나눌 수 없는 단위로 수행된다는 것을 의미한다. 즉 원자적 연산을 중단되지않고, 다른 연산과 간섭없이 완전히 실행되거나 전혀 실행되지 않는 성질을 가지고 있다. 쉽게 얘기해서 멀티스레드 상황에서 다른 스레드의 간섭 없이 안전하게 처리되는 연산이라는 의미이다.

예를 들어서 volatile int i =0와 같은 식이 있을 때 i의 오른쪽 값을 i에 대입하는 식 1개뿐이므로 둘로 쪼갤수 없는 원자적 연산이다.

하지만 i+=1 은 원자적 연산이 아니다. i의 값 읽기, i에 1더하기 , 그 값을 다시 i에 대입하기로 식이 나눌수 있기 때문이다. 코드 예시로 원자적이지 않은 식을 멀티 스레드에서 썻을때 어떤 문제가 생기는지 알아보자.

public class BasicInteger implements IncrementInteger {
    private int value;
    @Override
    public void increment() {
	value++; 
    }
    @Override
    public int get() {
        return value;
    }
}
    
  • value값은 인스턴스의 필드이기 때문에 여러 스레드가 공유할 수 있다. 이렇게 공유 가능한 자원에 ++같은 원자적이지 않은 연산을 사용하면 문제가 생길수 있다.
private static void test(IncrementInteger incrementInteger) throws InterruptedException {
	Runnable runnable = new Runnable() {
   
     @Override
      public void run() {
          sleep(10); 
          incrementInteger.increment();
      }
  };
	List<Thread> threads = new ArrayList<>();
	for (int i = 0; i < THREAD_COUNT; i++) {
    	Thread thread = new Thread(runnable);
    	threads.add(thread);
         thread.start();
        }
        
    for (Thread thread : threads) {
             thread.join();
		}
         int result = incrementInteger.get();
         System.out.println(incrementInteger.getClass().getSimpleName() +
         " result: " + result);

	}    
 }
  • 상수 만큼의 스레드를 생성하고 increment()메서드를 호출

  • 스레드를 1000개 생성했다면 메서드도 1000번 호출하기 때문에 결과는 1000이 되어야 하지만 실행하면 1000이 아닌 다른 숫자가 나온다

  • 이렇게 연산자체가 나눠진 경우에는 synchronized 블럭이나 Lock 등을 사용해서 안전한 임계 영역을 만들어야한다.



원자적 연산 - AtomicInteger

AtomicInteger를 사용하면 멀티스레드 상황에서 안전하게 증가 연산을 수행할 수 있다.

public class MyAtomicInteger implements IncrementInteger {
     AtomicInteger atomicInteger = new AtomicInteger(0);
     @Override
     public void increment() {
         atomicInteger.incrementAndGet();
     }
     @Override
     public int get() {
         return atomicInteger.get();
     }
}
  • new AtomicInteger(0): 초기값을 지정한다. 생략하면 0부터 시작한다.
  • incrementAndGet(): 값을 하나 증가하고 증가된 결과를 반환한다
  • get(): 현재값을 반환한다.
profile
자바를 사랑합니다

0개의 댓글

관련 채용 정보