CS/운영체제

Process, Thread & Thread-safe

개발하는고양이 2024. 2. 6. 17:44
반응형

Process

일단 프로세스부터 정리해보자. 실행중인 프로그램을 프로세스라고 한다. 프로세스는 독립된 개체로, 운영체제로부터 별도의 메모리 영역을 할당받으며, 서로에게 접근이 불가능하다.

현재 인스타그램과 카톡이 실행중인 상황

그렇다면, 여러개의 프로세스를 처리하기 위해서는 어떻게 해야할까?

IPC 라는 커뮤니케이션 기법 (공유메모리를 활용해서 프로세스끼리 서로 상태를 주고받는거라 생각하면된다.)

Thread

프로세스 안에서 실행되는 작업 단위를 스레드라고 한다.

하나의 프로세스는 여러개의 스레드가 포함된다. 스레드 또한 프로세스처럼 병렬로 처리가 가능하다.

프로세스안에 여러개의 스레드가 존재한다.

프로세스와 스레드의 차이점

프로세스는 서로의 데이터에 접근할 수 없지만 스레드는 프로세스 내부에 존재하기 때문에 프로세스 데이터 영역에 접근이 가능하다.

또한 스레드들끼리는 IPC없이도 서로의 데이터에 접근이 가능하다. 

스레드는 함수로 구현된다. 따라서 메모리의 스택 영역인 thread stack을 가지는데, 이곳은 프로세스가 가지는 스택 메모리 영역과는 별도의 공간이다.

프로세스는 4가지로 나눌수 있는 메모리 영역을 가지지만, 스레드는 thread stack 메모리만 가진다.

인스타그램 프로세스와 카카오톡 프로세스는 자원을 공유할 수 없다.

 

오류가 난다면?

한 프로세스를 실행하다가 오류가 나면, 다른 프로세스에는 영향이 없다.

다른 정수기에 영향을 미치지 않듯이

 

하지만 스레드는 프로세스의 공유 자원을 서로 접근하기 때문에 하나의 스레드에서 오류가 난다면 다른 스레드 또한 강제 종료가 된다.

좀비랑 같이 물먹는다고 생각해보자,,,;;

 

Thread-safe

멀티스레드는 하나의 프로세스가 여러 스레드를 동시에 처리하는 것을 말한다.

공유자원을 사용하기 떄문에 context-switching을 할때 공유하는 자원만큼 아낄 수 있고, 통신 부담이 적어 응답 속도도 빠르다.

하지만 위에서 본 것처럼 하나의 스레드가 모든 스레드 또는 모든 프로세스를 종료시킬 수 있다는 단점이 있다.

또한 자원을 공유하므로 동기화 문제가 발생한다.

따라서 멀티 스레드를 사용하려면 개발자가 신중하게 개발해야한다. Thread-safe 하게 만들어야된다.

 

Tread-safe란 멀티 스레드 환경에서 서로 다른 스레드들이 동시에 같은 것에 접근하여 이용해도 안전하다는 뜻이다.

자바에서는 Thread, Runnable을 이용해서 멀티 스레드를 구현한다. 이 상황 말고, 특정 클래스의 빈을 생성해 놓고 그 빈을 여러 곳에서 동시다발적으로 사용할 때 또한 이러한 동시성을 고려해야한다. 예를 들어 redis를 사용하기 위해 생성하는 LettuceConnectionFactory 클래스를 빈으로 등록할 때처럼 말이다.

 

ThreadLocal

thread-safe 하지 않은 클래스들을 위해서 thread local이 사용된다.

이 기능은,

여러 스레드에서 동시에 특정 변수를 접근할 때, 해당 변수가 다른 스레드에 의해서 변경되어 값이 다르게 나오는 것을 방지하기 위한 용도이다.

// Thread-safe한 변수를 사용하고 싶을 때
// ThreadLocal로 감싸준다.
ThreadLocal<Human> human = ThreadLocal.withInitial(() -> new Human());

 

ThreadLocal에 저장된 값은 각각의 스레드에서 독립적으로 복사된 변수를 갖게 된다. 복사된 변수를 통해 각 스레드들은 각자의 변수에 접근하므로 스레드1이 스레드3에 서로 영향을 받지 않는다.

 

Set, Get 메서드 살펴보기

ThreadLocalMap에 key-value 값으로 현재 threadlocal을 세팅한다.

해당 변수는 해당 스레드에서만 고유하게 사용하도록 한다.

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
}

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
}

참고

https://jerryjerryjerry.tistory.com/184

https://velog.io/@raejoonee/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4

https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html

반응형