qkrtkdwns3410

[TIL] 유데미 . 고성능을 강조한 Java 멀티스레딩, 병행성 및 병렬 실행 프로그래밍 전문가 되기

8 days ago
·
12 min read

섹션 1: 개요

1. 개요와 OS 기초

멀티 스레딩 목적과 개요

멀티스레딩이 필요한 이유

  • 응답성

    • 여러 사용자가 동시 요청시 대기 시간을 줄여야함.

      • 즉각적 반응 제공

    • UI 반응 속도 유지

      • 동영상 플레이어 등 실시간 반응이 필요한 어플

  • 성능

    • 단일 스레드보다 더 많은 작업을 같은 시간 안에 처리할 수 있다.

    • 여러 코어(CPU) 가 있는 경우 병렬로 작업이 가능해져서 처리 속도가 향상된다.

    • 대규모 서비스를 제공하는 경우 서버/컴퓨터 대수를 줄일 수 있다

2. 병행성(Concurrency) 멀티태스킹

  • 병행성

    • 멀티스레딩으로 여러 작업을 동시에 실행하는 듯한 효과 가능

  • 멀티 태스킹

    • 하나의 코어에서 여러 스레드를 빠르게 번갈아가며 실행

    • 사용자 입장에서는 여러 작업이 동시에 수행되는 것처럼 보인다.

    • 여러 코어가 있으면 실제로

      • 병렬 == Parallel

        • 실제로 여러 코어로 여러 작업

      • 병행 == Concurrency

        • 하나의 코어지만 코어 내부의 스레드들도 여러 작업을 수행함.

  1. 멀티 스레딩 프로그래밍 주의

    1. 스레드 간 공유 데이터 관리 문제, 동기화 문제 발생가능

    2. 뮤텍스, 세마포어 등의 동기화 기법을 올바르게 사용해야함

시스템 기본 동작

  1. 운영 체제

    1. 컴퓨터 전원 ON >> 디스크에서 메모리로 로드되는 특별한 프로그램

    2. 애플리케이션 <> 하드웨어(CPU) 간 상호작용을 중재

      • 개발자는 비즈니스 로직에 집중 가능

  2. 프로세스(Process)

    1. 실행 중인 애플리케이션의 인스턴스

    2. 코드, 힙, 파일, 프로세스 ID 등의 메타 데이터로 구성

    3. 프로세스 끼리는 서로 격리됨

  3. 스레드

    1. 프로세스 내부 실행 흐름의 단위

    2. 적어도 하나의 메인 스레드 가 존재한다.

    3. 스레드는 각가 스택명령어 포인터 를 가진다

      1. 스택

        • 함수의 지역 변수, 매개 변수 등을 저장하는 메모리 공간

      2. 명령어 포인터

        • 다음에 실행할 명령어 주소

    4. 멀티 스레드 어플리케이셔에서

      • 코드, 힙, 파일 등 프로세스 내 자원을 여러 스레드가 공유함.

    5. 스레드마다 서로 다른 함수를 동시에 수행 가능함.

2. 운영 체제 기초

컨텍스트 스위치

  • 정의

    • 하나의 스레드 실행을 중단하고 다른 스레드(or 프로세스) 로 전환하는 과정

  • 과정

    • 현재 스레드 레지스터, 캐시, 커널 리소스 상태 저장

    • 전환 대상 스레드 상태 CPU, 메모리에 복원

    • 대략적으로 이런 그림이다

      2546
  • 영향

    • 병행성 을 위해 필수적이지만

    • 오버헤드 가 발생한다

    • 너무 많은 스레드가 동시에 실행되는 경우, 컨텍스트 스위치 가 과도해서져서

      • 스래싱(thrashing) 을 유발하게 된다.

프로세스 VS 스레드 전환 비용

  • 프로세스 간 전환

    • 주소 공간이 달라서 리소스 교환 범위가 넓어 비용이 크다

  • 동일 프로세스 내 스레드 전환

    • 공유하는 리소스(코드, 힙 등) 이 많아서 전환 비용이 프로세스 간 전환보다 낮다

운영 체제 스레드 스케쥴링

  • CPU 코어 < 스레드 개수

    • 운영 체제 가 언제, 어떤 스레드를 실행할 지 결정한다.

  • 스케줄링 기법

    • First Come First Served(FCFS)

      • 도착 순서대로 실행한다

        • 긴 작업이 먼저 오면 나머지 스레드가 기아(Starvation) 현상이 발생함

        • 매우 짧은 중요도가 높은 작업이 있는데도 불구하고, 긴 작업때문에 병목이 발생함

    • Shortest Job First(SJF)

      • 짧은 작업부터 실행한다

        • 긴 작업은 계속 뒤로 밀릴 위험이 있음

    • 시간 분할(타임 슬라이스 / 라운드 로빈 ... )

      • 일정 시간 단위(epoke) 로 CPU 시간 분할하여 스레드에 할당한다.

        • 우선순위 기반 동적 스케줄링 기법임

          • 정적 우선순위(개발자 선정) + 동적 보너스(OS 자동 조정)

          • 실시간, 인터랙티브 스레드에 높은 우선순위를 할당한다

          • 이전 에포크에서 실행 시간이 부족했던 스레드도 일정 비율로 보완된다.

        • 내용이 좀 어려운듯

          1. 시간분할

            • 놀이기구를 2분씩 번갈아서 타는 행위임.

            • CPU 도 각 마찬가지로 각 프로그램에 일정 시간을 나눠서 실행 기회를 부여한다

          2. 우선순위 시스템

            • 정적 우선순위

              • VIP 티켓

                • 실시간 채팅앱 같은 프로그램은 더 자주 실행될 수 있도록 한다.

            • 동적 보너스

              • 오래 기다린 손님에게 주는 우선권임

                • OS 가 자동으로 오래 기다린 프로그램에게 보너스 점수를 부여

          3. 보완 시스템

            • 이전에 CPU 를 덜 사용한 프로그램에게 다음 번에 더 많은 기회를 제공함.

4. 멀티 스레드 vs 멀티 프로세스

구분

멀티 스레드 접근

멀티 프로세스 접근

장점

  • 데이터 리소스간 공유가 용이하다

  • 스레드 간 전환 비용이 낮다

  • 응답성 UP, 리소스 활용 UP

  • 프로세스 간 격리로 보안-안정성 향상

  • 한 프로세스가 다운되어도 다른 프로세스 영향 없음

상황

  • 여러 기능이 많은 데이터를 공유하면서 처리해야 할 때

  • 보안, 안정성이 최우선인 경우

  • 서로 크게 연관 없는 기능을 별도의 프로그램으로 분리해서 독립 실행하는 경우

단점

  • 부분 기능 중 하나만 다운돼도 전체 어플리케이션에 영향이 있음

  • 스레드 간의 동기화 복잡성이 증대

  • 프로세스 간 통신(IPC) 비용이 높음

  • 리소스 사용량이 멀티 스레드에 비해 상대적으로 많음

스레드 실습

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("스레드 실행 중 몇번이고: " + Thread.currentThread().getName());
            }
        });
        
        System.out.println("스레드 실행 이전 몇번이고: " + Thread.currentThread().getName());
        thread.start();
        System.out.println("스레드 실행 이후 몇번이고: " + Thread.currentThread().getName());
        
        Thread.sleep(10000);
    }
}

//

스레드 실행 이전 몇번이고: main
스레드 실행 이후 몇번이고: main
스레드 실행 중 몇번이고: Thread-0
  • 둘다 main 스레드로 찍히는데

    • 이는 스레드가 시작된다고 해서 바로 생기는게 아니라

    • 비동기적으로 생겨나서 여전히 start() 후에도 main 스레드가 출력된다고한다.

    • 실제로 스레드가 run()하는 순간 새 스레드가 생겨남.

    2547
  • 에서 보듯이 (라고 했는데 안보이긴함)

    • 메인 스레드는 이미 DestroyJavaVM 에 의하여 종료된 상태고

  • 2548
  • main 내의 새로운 워커 스레드가 실행 중이라는 것을 알 수 있음.

예외 처리 핸들러 설정 관련

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                throw new RuntimeException("Intentional Exception");
            }
        });
        
        //예외 처리 핸들러 설정
        /*스레드 내에서 발생한 예외를 처리하기 위하여 setUncaughtExceptionHandler() 를 사용가능
        *
        * 캐치되지 않은 예외가 발생시 지정된 핸들러가 호출되도록 한다.
        *
        * 왜 쓰냐?
        *
        * 멀티 스레드에서 각 스레드는 독립적으로 실행되는데
        *
        * 특정 스레드 내에서 예외가 발생하고 적절하게 처리하지 않는다면,
        *
        * 해당 스레드는 비정상적으로 종료된다.
        *
        * 예외 처리 핸들러 설정시 스레드가 비정상적으로 종료되더라도, 애플리케이션 전체가 즉시 종료되지 않고, 다른 스레드들이 계속 정상적으로 동작함.
        * */
        
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("A critical error happened in thread " + t.getName()
                        + " the error is " + e.getMessage());
            }
        });
        
        thread.start();
    }
}

//

A critical error happened in thread Thread-0 the error is Intentional Exception

종료 코드 0(으)로 완료된 프로세스

다음 강의

  • 스레드 생성 2부







새는 알에서 빠져나오려고 몸부림친다. 알은 세계다. 태어나려고 하는 자는 하나의 세계를 파괴하지 않으면 안 된다. 그 새는 신을 향해 날아간다