카테고리 없음

thread unsafe

casylm 2024. 7. 16. 22:55

thread unsafe 가 무엇?

동기화가 되어있지 않는 환경. 동기화는 멀티 쓰레드 환경에서 일어난다. 

 

멀티 쓰레드란?

다수의 쓰레드가 동시 실행되는 환경을 의미한다. 멀티 쓰레드 환경에서는 병렬로 처리가 진행되기 때문에, 쓰레드간 자원에 동시 접근하여 삽입, 삭제와 같은 연산을 수행 할 경우 개발자의 의도와는 다른 결과가 도출 될 수 있다. 

 

이러한 문제를 예방하는 것이 synchronized 키워드 이다. 메서드 앞에 synchronized 키워드를 삽입하면, 동기화 처리가 되어 동시 접근을 방지해준다. 

 

동기화란?

서로가 알고 있는 것을 일치시키는 것이다. 컴퓨터의 영역에서는 데이터를 일치시키는 것을 의미한다. 이를 위해서는 프로세스의 순차적 작업이 이루어져야 한다. 

 

thread unsafe 대표 예시

arrayList

arrayList는 대표적인 thread unsafe의 예제이다. 결론부터 말하자면, arrayList는 synchronized 키워드를 가지고 있지 않으며, 멀티 쓰레드 환경에서 삽입, 삭제 동작 시 문제가 발생 할 가능성 이 있다.

public static void main(String[] args) {
     List<String> list = new ArrayList<>();
     
    // 스레드1, 스레드2가 동시에 실행 가정 
    list.add("A"); // 스레드1 실행 가정 
    list.add("B"); // 스레드2 실행 가정 
    System.out.println(list);
}

다음 상황에서 스레드 1,2가 동시에 실행 되며 2가 조금 더 빨리 자원을 선점한다고 가정해보자. 개발자의 의도는 A 가 list에 추가된 후 B를 삽입하는 것이다. 하지만, 이 경우 개발자의 의도와는 다른게 B->A의 순서로 삽입 작업이 일어날 수 있다.

 

String builder

public class thread2 {
    public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder();

        new Thread(() -> {
            for(int i=0; i<10000; i++) {
                stringBuilder.append(1);
            }
        }).start();

        new Thread(() -> {
            for(int i=0; i<10000; i++) {
                stringBuilder.append(1);
            }
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("StringBuilder.length: "+ stringBuilder.length()); // thread unsafe 함
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

 

StringBuilder.length: 14747

 

스레드를 2개 생성하고 각 스레드 당 10000의 + 연산을 수행하였다. 정상적인 경우 20000이 출력되어야 하지만, 14747 이라는 숫자가 출력되었다. 이를 통하여, 연산 수행 중 동시 접근에 의해 누락되는 경우가 있다는 것을 알 수 있다.

 

 

실생활 예시

은행 입출금 프로세스

부부가 은행에 방문하여 남편 A가 은행 창구에서 현재 잔액이 100만원인 C계좌에 50만원을 입금하려고 한다. 비슷한 시각에, 아내 B가 ATM에서 20만원을 입금한다. 

올바른 처리 순서는

1) 100만원인 계좌를 읽고 50만원을 더해 150만원을 계좌 C에 새로 업데이트 한다

2) 잔액이 150만원인 계좌에서 20만원을 입금하고 최종적으로 170만원의 잔액이 계좌 C에 작성된다

이다.

정상 case

 

위 작업들이 병렬적으로 진행된다면 어떤 경우가 일어날 수 있을까

1) 은행 창구 시스템에서 100만원 계좌를 읽었다. 

2) ATM에서 100만원 계좌를 읽고 20만원 입금 후 잔액 120을 업데이트 한다.

3) 은행 창구 시스템에서 읽은 100만원에 50만원을 더하여 최종적으로 150만원을 계좌 C에 작성한다.

오류 case

 

통장에 170만원이 기장되어 있을 것이라 생각했던 부부는 150만원의 잔액을 보고 은행에 민원을 제기한다.

멀티 쓰레드 환경에서 리스트의 메서드를 무작정 호출한다면, 위의 ATM 예시처럼 리스트에 값이 올바르게 적재되지 않을 수 있다.

 

https://velog.io/@eunjin/OS-%EC%8B%B1%EA%B8%80%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%A9%80%ED%8B%B0%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%9D%98%EB%AF%B8

 

[OS] 싱글스레드, 멀티스레드의 의미

먼저 프로세스와 스레드의 차이를 알아보았다. 프로세스: 운영체제로부터 자원을 할당받는 작업의 단위 디스크로부터 메모리에 적재되어 운영체제로부터 주소 공간, 파일, 메모리 등을 할당받

velog.io

https://devwithpug.github.io/java/java-thread-safe/

 

자바에서 동시성 문제를 해결하는 3가지 키워드

개요

devwithpug.github.io

https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-ArrayList-vs-Vector-%EB%8F%99%EA%B8%B0%ED%99%94-%EC%B0%A8%EC%9D%B4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0#arraylist%EB%8A%94_%EB%8F%99%EA%B8%B0%ED%99%94%EA%B0%80_%EB%90%98%EC%96%B4%EC%9E%88%EC%A7%80_%EC%95%8A%EB%8B%A4