Thread - Network

[Thread] Java Thread

Joo.v7 2024. 9. 11. 23:25

1. Process (프로세스)

  • Process Scheduling (프로세스 스케줄링)
  • Process Scheduling 방식
  • Process Scheduling Alogrithm
  • Process 상태 변화

2. Thread

  • Main Thread
  • Single Thread
  • Multi Thread
  • Thread Life Cycle
  • Thread 상태 변경 Method

3. Monitor

4. Thread & Concurrency

  • Semaphore(세마포어)
  • Mutex(뮤 텍스)
  • Synchronized

5. Deadlock

  • Hold and Wait (점유 대기)
  • Circular Wait (순환 대기)
  • Starvation (기아 상태)
  • Livelock

6. Thread Pool 실습


1. Process (프로세스)

  • 컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램.
  • 프로그램: 보조 기억 장치에 저장된 실행 코드 / 프로세스: 프로그램을 구동하여 메모리상에서 실행되는 작업 단위.
  • 대부분의 OS는 시분할 방식을 지원.
    (멀티 태스킹: 같은 시간에 여러 개의 프로그램을 실행하는 시분할 방식)

프로세스 메모리 구조.

 

Process Scheduling (프로세스 스케줄링)

 CPU 할당 순서 및 방법을 결정하는 일.

 

Process Scheduling 방식

  • Non-preemptive (비선점형) : 프로세스가 스스로 다음 프로세스에 자리를 넘겨주는 방식.
  • Preemptive (선점형) : OS가 강제로 프로세스의 사용권을 통제하는 방식.

 

Process Scheduling Alogrithm

  • FCFS (First Come First Serve)
    • CPU에 먼저 도착하는 순서대로 프로세스를 할당 (Non-preemptive 방식)
  • SJF (Short Job First)
    • 프로세스의 수행 시간이 짧은 순서대로 프로세스를 할당. (Starvation이 발생할 수 있다)
  • Round Robin 
    • 각 프로세스가 동일한 크기의 할당 시간을 갖고, 시간이 끝나면 자동으로 Ready Queue의 제일 뒤로 할당됨.
  • Priority Processing
    • 기준을 정해서 프로세스에 우선순위를 부여해, 우선순위가 제일 높은 프로세스에 CPU 할당.
      (Starvation 해결 -> 에이징 방식: 오래 대기한 프로세스의 우선순위를 높임)

* Java의 Thread 스케줄링: 우선순위 기반 라운드 로빈 방식.
(우선순위 방식은 Thread 객체에 우선 순위 번호를 부여하는 방식으로 제어, 1부터 10까지의 범위로 설정할 수 있으며, 우선순위를 부여하지 않으면 기본적으로 5의 우선순위를 부여 받습니다. 우선순위의 변경을 위해서 setPriority 메소드를 이용할 수 있습니다. setPriority 메소드에 Thread 클래스의 Thread 우선순위 상수를 이용할 수도 있습니다.)

 

Process 상태 변화

 하나의 프로그램이 실행되면 해당 프로그램에 대응하는 Process가 생성되어, Ready list의 끝에 들어감.

  • Dispatch
    • Ready 리스트의 맨 앞에 있던 Process가 CPU를 점유하게 되는 것.
  • Block
    • Running 상태의 process가 시간을 다 쓰기 전에 입출력 동작이 필요한 경우, CPU 반납하고 Blocked됨.
  • Wakeup
    • 입출력 종료 등 기다리던 사건이 일어났을 때.
  • Timeout
    • OS가 clock interrupt를 두어서, Process가 일정 시간 동안(time slice)만 CPU 점유.

 


2. Thread

  •  Process 내에서 실행되는 여러 개의 실행 단위.
  • 각각 thread는 독립적인 작업을 수행, 각각 독립된 stack과 pc register 값을 가지고 있다.

Thread 클래스 상속

 

Main Thread

  • Java 프로그래밍을 실행하면 하나의 thread가 생성 후 즉시 실행, 이를 일반적으로 Main Thread라 한다.

 

Single Thread

  • 하나의 Process에서 오직 하나의 thread(Main thread)로만 작업 진행.
  • 장점
    • 자원 접근에 대한 동기화를 고려하지 않아도 된다.
    • Context switch (문맥 교환) 작업을 요구하지 않는다.
      (현재 진행하는 Task(Process, Thread)의 상태를 저장하고, 다음 진행할 Task의 값을 읽어 적용하는 과정)
    • 개발 난이도가 쉽고, CPU, Memory를 적게 사용(비용 감소)
  • 단점
    • Multi CPU 활용 못함.
    • 연산량이 많은 작업의 경우, 해당 작업이 완료되어야 다음 작업 진행 가능.
    • Single Thread는 Error 처리를 못하는 경우 중지됨.

 

Multi Thread

  • 프로그램 내에서 두 개 이상의 동작을 동시에 실행.
  • 하나의 Process를 다수의 실행 단위로 구분하여 자원을 공유
  • 장점
    • 응답성
      • 프로그램 일부가 중단되거나, 긴 작업을 수행하더라도 프로그램 수행이 지속적으로 유지.
      • Multi Thread 환경에서는 error 발생 시, 새로운 Thread를 생성해서 error를 극복.
    • 경제성
      • 프로세스 내 자원들과 메모리를 공유하기 때문에, 메모리 자원과 시스템 공간을 효율적으로 활용.
      • Thread 간 통신에서도 데이터를 주고 받을 수 있으며, Process간의 Context switching과는 달리 thread간의 context switching은 캐시 메모리를 비울 필요가 없기 때문에 더 빠르게 동작.
      • Multi Core CPU 환경에서는 각각의 thread가 다른 processor에서 병렬로 수행.
  • 단점
    • Context switching, 동기화 등의 이유로 Single Core Multi Threading은 Thread 생성 시간이 오히려 오버헤드로 작용해 Sigle thread보다 느릴 수 있다.
    • 공유자원을 서로 다른 thread가 동시 접근 하는 경우, thread 내에서는 Heap 영역을 공유하기 때문에 다른 thread에서 사용 중인 변수나, 자료구조에 접근하여 엉뚱한 값을 읽어오거나 수정할 수 있다.
    • 반드시 동기화 처리를 해야 한다 (동기화 비용 발생)
    • 개발 난이도가 높고, 자원 사용량도 많다. 

1회 실행, 자원이 공유되는 문제 발생.
2회 실행, 자원이 공유되는 문제 발생

 

Thread Life Cycle

  • New: Thread가 실행 준비를 완료한 상태(Thread 객체가 생성된 상태)로, start() 메소드 호출하기 전 상태.
  • Runnable: start()가 호출되어 실행될 수 있는 상태 (Thread Scheduling에 따라 CPU를 할당 대기 상태)
  • Wait: 다른 thread가 통지할 때까지 기다리는 상태.
  • Timed_wait: 정해진 시간 동안 기다리는 상태.
  • Blocked: 사용하고자 하는 객체의 잠금(lock)이 풀릴 때까지 대기하는 상태.
  • Terminated: 실행이 종료된 상태.

 

Thread 상태변경 Method

interrupt() 스레드에서 InterruptedException 예외를 발생시켜 예외 처리 코드에서 실행 대기 상태로 가거나 종료 상태로 가도록 함.
notify() wait() 메서드에 의해 Wait 상태에 있는 스레드를 Runnable 상태로 만듦.
notifyAll() wait() 메서드에 의해 Wait 상태에 있는 모든 스레드를 Runnable 상태로 만듦.
sleep(long millis) 주어진 시간 동안 스레드를 Timed_wait 상태로 만듦. 주어진 시간이 지나면 자동으로 Runnable 상태로 바뀜.
sleep(long millis, int nanos) 밀리초와 나노초를 지정하여 주어진 시간 동안 스레드를 Timed_wait 상태로 만듦. 주어진 시간이 지나면 자동으로 Runnable 상태로 바뀜.
join() 메인 스레드가 다른 스레드들이 종료될 때까지 기다리게 하여 스레드 간의 순서를 조절하고 동기화할 수 있음.
join(long millis) 주어진 시간 동안 다른 스레드가 종료될 때까지 기다림. 시간 경과 후 자동으로 Runnable 상태로 바뀜.
join(long millis, int nanos) 밀리초와 나노초를 지정하여 주어진 시간 동안 다른 스레드가 종료될 때까지 기다림. 시간 경과 후 자동으로 Runnable 상태로 바뀜.
wait() Block 상태에서 스레드를 Wait 상태로 만듦. notify() 또는 notifyAll()에 의해 Runnable 상태로 변경됨.
wait(long millis) 주어진 시간 동안 스레드를 Wait 상태로 만듦. 시간이 지나면 자동으로 Runnable 상태로 바뀜.
wait(long millis, int nanos) 밀리초와 나노초를 지정하여 주어진 시간 동안 스레드를 Wait 상태로 만듦. 시간이 지나면 자동으로 Runnable 상태로 바뀜.
yield() 실행 중인 스레드를 Wait 상태로 변경하고, 우선순위가 동일하거나 높은 순위의 다른 스레드에게 CPU 자원을 양보함.

 

 


3. Monitor (모니터)

 Monitor는 Java에서 Thread간의 동기화(synchronization)를 관리하는 중요한 개념으로, 특정 객체에 대한 접근을 제어하여 동시에 여러 Thread가 동일한 자원에 접근하지 못하도록 한다. 이를 통해 데이터의 일관성을 유지, 동시성 문제를 방지할 수 있다.

  • Mutual Exclusion(상호 배제) : 한 번에 하나의 Thread만 Monitor에 진입 가능.
  • Condition Variables(조건 변수): Thread가 특정 조건을 기다리거나, 다른 Thread에 신호를 보내기 위해 사용됨.
    (Java에서는 wait(), notify(), notifyAll() 메소드를 통해 구현됨)

 


4. Thread & Concurrency

 Thread는 하나의 process 내에서 자원을 공유하면서 여러 개가 동시에 실행될 수 있다.

  • Race Condition(경쟁 조건)
    • 둘 이상의 Thread가 동시에 공유 자원 접근 시 발생.
  • Critical Section(임계 구역)
    • 병렬 컴퓨팅에서 둘 이상의 Process 또는 Thread가 동시 접근이 허용되지 않는 공유 자원에 접근하는 코드의 블록을 말한다. Critical section은 thread에서 작업에 필요한 최소한의 시간 동안만 유지되어야 하고, 작업이 완료된 후에는 반드시 해제되어야 한다. 따라서 한 thread가 citical section에 들어가고 작업 중 이라면, 나머지 thread들은 완료될 때까지 대기해야 한다.
  • Mutual Exclusion(상호 배제)
    • Critical section의 access를 하나의 Process 또는 Thread로 제한하는 것.

 

4-1. Semaphore(세마포어)

 Semaphore Class는 Thread간의 동기화(Synchronization)을 위해 사용된다. 객체 생성시 파라미터 인자로 전달받은 수 만큼 Thread의접근을 허가한다.

  • acquire()
    • 허가 획득 시도.
    • 허가 대기.
  • release()
    • 허가 반환.
    • 대기 중인 thread 알림.

 

4-2. Mutex(뮤 텍스)

 Mutex는 한 번에 하나의 Thread만 임계 구역에 접근할 수 있도록 보장하는 잠금 메커니즘.

  • lock()
    • Mutex를 lock 한다. 다른 thread가 이미 mutex를 lock 한 상태라면, unlock 될 때까지 대기.
  • unlock()

 

4-3. Synchronized

 동기화는 여러 Thread가 동시에 하나의 공유 자원에 접근하지 못하도록 막아주는 개념이다.

  • synchronized 메소드
    • 메소드 전체를 synchonization하여, 한 번에 하나의 thread만 접근할 수 있도록 한다.
public synchronized long increaseAndGet(){
    count = count + 1;
    return count;
}

 

  • synchronized block
    • 메소드 내의 특정 블록만 동기화하여, 필요한 부분만 보호한다.
public long increaseAndGet(){
    synchronized (this) {
        count = count + 1;
    }
    return count;
}

 

정리

특징 Semaphore (세마포어) Mutex (뮤텍스) synchronized
목적 여러 스레드가 자원을 제한된 수만큼 접근하도록 제어 단일 스레드가 자원에 접근하도록 제어 특정 코드 블록이나 메서드에 대한 동기화
동기화 대상 여러 개의 스레드 단일 스레드 단일 스레드
상태 카운터 값 (0 이상) 이진 상태 (0 또는 1) 내부적으로 뮤텍스 사용
소유권 소유권 없음 소유권 있음 (소유한 스레드만 해제 가능) 소유권 있음 (해당 객체의 모니터 락)
사용 예 리소스 풀, 연결 풀 임계 구역 보호 메서드나 코드 블록 동기화
초기화 초기 카운터 값 설정 필요 초기화 필요 없음 초기화 필요 없음
해제 가능 여부 다른 스레드가 해제 가능 소유한 스레드만 해제 가능 소유한 스레드만 해제 가능
교착 상태 발생 가능 발생 가능 발생 가능

 

 


5. Deadlock (교착 상태)

 Deadlock은 mutual excusion 과정에서 자원 접근 권한의 획득 - 반환 관계의 꼬임으로 발생.

Hold and Wait (점유 대기)

  • 두 개의 Thread가 서로 다른 lock을 획득한 후, 다른 lock을 기다리며 무한 대기 상태에 빠짐.

Circular Wait (순환 대기)

  • 서로 다른 자원을 점유하면서 서로의 자원을 기다리는 상태.

Starvation (기아 상태)

  • 다른 process나 thread가 공유 자원의 접근 권한을 지속적으로 가짐으로써 발생.
  • 운영 방식 등의 이유로 해당 process나 thread가 공유 자원의 접근 권한을 획득하지 못해 무한 대기 상태에 빠짐.

Livelock

  • 두 개 이상의 Thread가 서로의 진행을 방해하지 않으면서도, 실제로는 작업을 완료하지 못하고 무한히 반복되는 상태.
    ex) 두 thread가 서로의 상태를 확인하고, 상대방이 특정 조건을 만족할 때까지 기다리는 상황.

 


6. Thread Pool 실습

https://github.com/Joo-v7/NHN-Academy-Thread

 

GitHub - Joo-v7/NHN-Academy-Thread: NHN Academy boot camp

NHN Academy boot camp. Contribute to Joo-v7/NHN-Academy-Thread development by creating an account on GitHub.

github.com

 


 

 

출처: https://github.com/nhnacademy-bootcamp/java-thread/tree/main/docs

'Thread - Network' 카테고리의 다른 글

[Network] HTTP와 GET / POST 방식  (0) 2024.10.05
[Network] Java Socket  (0) 2024.09.30