멀티쓰레드 프로그래밍

dev_314·2022년 11월 23일
0

자바 라이브 스터디

목록 보기
17/18

Process & Thread

Process

프로그램을 실행하기 위해 필요한 모든 자원을(메모리 등), OS로부터 할당받은 뒤 추상화한 것(?)

한 번에 여러 프로그램을 실행할 수 있음 = 멀티태스킹 = 멀티 프로세스

Thread

프로세스 내부에서 실질적으로 작업을 수행하는 주체
하나의 프로세스는 하나 이상의 쓰레드로 구성됨
aka. light weight process (경량 프로세스)

Slack을 예로 들면

  1. 알람이 울리면서
  2. 새로운 Thread(게시물)이 업데이트 되면서
  3. 동시에 글을 작성할 수 있음

이는 여러 Thread가 각각의 역할(알림, 게시물 업데이트, 글 작성)을 수행하기 때문이다.


IntelliJ Process에서 85개의 Thread가 각자의 역할을 수행하는 중이다.

Process, Thread 비교

쓰레드를 생성하는 작업이, 프로세스를 생성하는 작업보다 비용이 적게 든다.
쓰레드를 전환하는 작업이, 프로세스를 전환하는 작업보다 비용이 적게 든다. (Context Switching)
각 쓰레드는 자신만의 고유한 Stack 영역을 가지고, 나머지 영역(Code, heap, Data)은 공유한다. 이러한 특성 덕분에, 프로세스보다 효율적인 Context Switching이 가능하다는 장점이 있다.

그렇다고 멀티 쓰레드 프로그램이 항상 좋은건 만은 아니다.

여러 쓰레드가 자원을 공유하기 때문에

  1. 쓰레드가 자원에 동시에 접근하게 되면 교착 상태에 빠질 수 있다. (Dead Lock)
  2. 자원의 동기화를 항상 신경써야 한다. (Synchronization)

또한 여러 Thread들이 어떤 순서로 실행되어야 할지를 고려해야한다. (starvation)

Thread 클래스와 Runnable 인터페이스

자바는 두 가지 방법의 쓰레드 구현 방법이 있다.

Thread 클래스

A Thread클래스는 프로그램을 실행하는 thread이다.JVM은 app이 동시에 실행될 수 있는 멀티 스레드를 지원한다.

모든 쓰레드는 우선순위가 있다. 높은 우선순위를 가진 쓰레드는 상대적으로 낮은 우선순위를 가진 쓰레드보다 먼저 실행된다.

각 쓰레드는 deamon 쓰레드로 마킹될 수도 있다.

특정 쓰레드에서 실행중인 코드에서 새로운 쓰레드 객체를 만들면, 새로 생성된 쓰레드는 자신을 생성한 쓰레드와 동일한 우선순위를 갖는다.

또한 자신을 생성한 쓰레드가 deamon이면, 새로 생성된 쓰레드도 deamon이다.

JVM이 시작되면(일반적으로 메인 메소드를 호출한 경우), 보통은 Single&non-daemon 쓰레이드이다.

JVM은 다음 조건을 만날 때 까지 계속 쓰레드를 실행시킨다.

  1. 클래스 런타임의 exit 메소드가 호출되고, security manager가 종료 작업 수행을 허용한 경우
  2. deamon 쓰레드가 아닌 모든 쓰레드가 종료된 경우
    2-1. 메소드가 정상적으로 return
    2-2. Exception 발생
public class Thread implements Runnable {
	...
}
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("this is my Thread");
    }
}

public class Main {

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start(); // this is my Thread
    }
}

Runnable 인터페이스

Runnable인터페이스는 클래스의 인스턴스가 쓰레드에서 실행되도록 의도된 클래스에의해 구현되어야 한다.

구현 클래스는 반드시 파라미터가 없는 run이라는 이름의 메소드를 override해야한다.

활성화된 상태에서 코드를 실행시키고 싶은 객체들을 위해 일반적인 프로토콜을 제공하기 위해 사용됨

예를 들어, RunnableThread클래스에서 구현된다.

활성화된 상태는 단순히 쓰레드가 실행되고 아직 정지되지 않은 상태를 의미한다.

RunnableThread를 상속받지 않고도 클래스가 active할수 있는 방법을 제공한다.

RunnableThread의 메소드들 중, run만을 override할 때 사용한다.

public class YourThread implements Runnable {
    @Override
    public void run() {
        System.out.println("this is your Thread");
    }
}

public class Main {

    public static void main(String[] args) {
        Thread yourThread = new Thread(new YourThread());
        yourThread.start(); // this is your Thread
    }
}

Deamon Thread

참고
[Java] 데몬 스레드(Daemon Thread) 의미와 예제

Thread 성질 살펴보기

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("this is my Thread " + i);
        }
    }
}

public class YourThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("this is your Thread " + i);
        }
    }
}

public class Main {

    public static void main(String[] args) {
        Thread myThread = new MyThread();
        myThread.start();

        Thread yourThread = new Thread(new YourThread());
        yourThread.start();
    }
}

싱글쓰레드의 경우 myThread의 start작업이 종료되어야, youtThread의 start작업이 실행된다.

멀티 쓰레드는 그렇지 않다.

쓰레드의 상태

쓰레드는 State enum을 통해 state를 표현(관리)한다.

StatusDescription
NEW쓰레드가 생성되었으나, 아직 시작되지 않은 상태
RUNNABLEJVM에서 실행중인 상태
BLOCKEDmonitor lock얻을때 까지 block된 thread 상태
WAITING기다리는 상태
TIMED_WAITING특정한 시간동안 WAITING인 상태
TERMINATED실행을 완료한 상태

RUNNABLE

JVM에서 실행중이나, 프로세서와 같은 리소스를 획득하기 위해 기다리는 중일 수도 있다.

BLOCKED

blocked state의 쓰레드는 synchronized block(영역) 또는 메소드에 진입하기 위해, 또는 Object.wait을 호출한 뒤, 다시 synchronized block/method에 진입하기 위해 monitor lock을 기다린다.

WAITING

다음의 상황에서 쓰레드가 WAITING상태가 될 수 있다.

  1. Object.wait with no timeout
  2. Thread.join with no timeout
  3. LockSupport.park

WAITING 상태의 쓰레드는 다른 쓰레드에서 특정 행동을 하길 기다린다.

예를 들어

  1. Object.wait를 호출한 쓰레드 객체는, 다른 쓰레드에서 Object.notify 또는 Object.notifyAll를 호출하길 기다린다.
  2. Thread.join을 호출한 쓰레드 객체는, 다른 쓰레드가 종료(terminate)되기를 기다린다.

TIMED_WAITING

다음의 상황에서 쓰레드가 TIMED_WAITING상태가 될 수 있다.

  1. Thread.sleep`
  2. Object.wait with timeout
  3. Thread.join with timeout
  4. LockSupport.parkNanos
  5. LockSupport.parkUntil

Monitor Lock

참고
Java Monitor(Intrinsic Lock)와 Explicit Lock의 이해 – Biased/Lightweight/Heavyweight Lock vs ReentrantLock

쓰레드의 우선순위

자바의 Thread Scheduling

참고
Thread Scheduler in Java

Main 쓰레드

동기화

데드락

profile
블로그 이전했습니다 https://dev314.tistory.com/

0개의 댓글