Skip to content

쓰레드 (Thread)

SeoSiun edited this page Jul 17, 2023 · 1 revision

Thread

  • cf) 프로세스(process) : 실행중인 프로그램

    • 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것
    • 프로그램에 사용되는 데이터와 메모리 등의 자원, 쓰레드로 구성
  • 쓰레드 (thread): 프로세스 내에서 실제로 작업을 수행하는 주체

    • 프로세스에는 하나 이상의 쓰레드가 존재하여 작업을 수행함.
    • 이때, 두 개 이상의 쓰레드를 가지는 프로세스를 멀티쓰레드 프로세스(multi-threaded process)라고 함.
  • 쓰레드는 user thread, kernel thread 두 종류가 있음.

User Thread (사용자 스레드)

  • 커널 영역의 상위에서 지원되며, 일반적으로 사용자 레벨의 라이브러리를 통해 구현되며, 라이브러리는 스레드 생성 및 스케줄링 관련 관리 기능을 제공함.
  • 동일한 메모리 영역에서 쓰레드가 생성 및 관리되므로 속도가 빠름. (스레드가 생성된 프로세스에 의해 제어됨)
  • 하나의 스레드가 block되면 다른 모든 스레드도 block되게 된다.
    • 커널에서는 사용자 스레드의 인식하지 못하기 때문에 해당 프로세스를 block시키기 때문
    • 프로세스 1개에 커널 스레드 1개가 할당되어, 같은 프로세스 내의 스레드 n개 가 1개의 커널 스레드를 공유함.

Kernel Thread (커널 스레드)

  • 운영체제가 지원하는 스레드 기능으로 구현되며, 커널이 스레드의 생성 및 스케줄링 등을 관리
  • 따라서 스레드가 중단되더라도, 커널은 프로세스 내의 다른 스레드를 중단시키지 않고 계속 실행시켜 준다.
  • 멀티 프로세싱 환경에서 커널은 여러 개의 스레드를 각각 다른 CPU에 할당할 수 있다.
  • 하지만 사용자 스레드에 비해 생성 및 관리가 느리다는 단점이 있음

Thread 생성 및 실행 in Java

Runnable

  • Runnable Interface를 구현하는 방법

  • 보통 Runnable Interface를 구현하는 방법을 더 많이 씀

    (Thread class를 상속받으면 다른 클래스를 상속할 수 없으므로)

  • Runnable은 아래와 같이 정의되어 있다.

    package java.lang;
    
    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }

⇒ Runnable을 구현한 클래스에서 run()을 메소드를 구현한 뒤

Runnable을 구현한 클래스의 인스턴스를 Thread의 생성자로 넘겨

Thread 객체를 생성한 뒤 Thread.start()로 실행할 수 있다.

public class Test implements Runnable {
	public void run() {
			// Do some task
	}
}

public static void main(String[] args {
	Thread thread = new Thread(new Test());
	thread.start();  // Test.run() 실행
}

Thread

  • Thread class를 상속받는 방법

  • Thread class는 Runnable Interface를 implement한 클래스

  • Thread는 아래와 같이 정의되어 있다.

    package java.lang;
    
    public
    class Thread implements Runnable {
    
    		...
    
        /* What will be run. */
        private Runnable target;
    
    		...
    
    		public void run() {
            if (target != null) {
                target.run();
            }
        }
    	
    		...

⇒ Thread를 상속한 클래스에서 run() 메소드를 구현한 뒤 Thread.start()를 통해 구현한 run()을 실행시킬 수 있다.

Java Multi Threading Model

  • Java 프로그램 실행시, JVM 프로세스가 동작하고, JVM 프로세스 내에서 GC 등 여러 개의 Thread가 실행됨.

    • 프로세스 생성에는 많은 시간, 자원이 필요하기 때문에 여러 개의 프로세스가 아닌, 스레드를 사용
  • 스레드가 실행되기 위해서는 CPU 스케줄러가 해당 스레드를 CPU에 스케줄링해야 하는데,

    커널에서는 사용자 스레드의 존재를 알지 못하기 때문에, CPU 스케줄링의 대상이 되지 못한다.

    따라서 사용자 스레드는 커널 스레드에 매핑되어 실행된다.

  • 사용자 스레드와 커널 스레드를 매핑하는 방법에는 아래 3가지가 있다.

many-to-one (Green Thread Model)

  • 여러 개의 유저 스레드를 하나의 커널 스레드로 맵핑하는 방식
    • 여러 스레드 중 하나가 block되면 전체 프로세스가 block됨
  • JVM이 OS 스레드를 사용하지 않고 유저 스레드만을 이용 (java 초기 버전의 스레드 모델)
  • 동기화 및 자원공유가 용이 → 실행시간 단축
  • 이 경우 멀티 코어 환경에서도 한 번에 하나의 user thread만이 처리될 수 있으므로, 멀티 코어의 장점을 얻을 수 없다는 단점이 있음. (병렬처리 불가)
  • 현재는 거의 사용되지 않고 있음

one-to-one

  • 유저 스레드 하나를 하나의 커널 스레드에 맵핑하는 방식
  • 따라서 하나의 유저 스레드가 block되더라도 다른 스레드가 실행될 수 있어 병렬 실행이 용이하다.
  • 각 스레드를 다른 코어에서 동시에 실행시키는 등 멀티코어 환경을 활용할 수 있음!
  • 하지만 이 경우 사용자 스레드를 생성할 때마다 커널 스레드를 만들어야 하는데, 커널 스레드 수가 너무 늘어나면 시스템 성능에 부담을 줄 수 있다는 문제가 있음. (스레드 개수를 무한정 늘릴 수는 없다!)

many-to-many (Native Thread Model)

  • 여러 개의 유저 스레드를 여러 개의 커널 스레드로 맵핑하는 방식

  • JVM이 OS의 도움을 받아 스레드를 관리 (JDK 1.3 이후 자바의 스레드 모델)

  • many-to-many 방식과 one-to-one 방식의 문제점을 해결하기 위해 등장-!

    • many-to-many에서 하나의 스레드가 중단되면 다른 모든 스레드도 중단되는 문제와 one-to-one에서 스레드 개수 제한 문제를 해결!
  • 멀티코어 시스템을 활용할 수 있음

  • 스레드 동기화 및 자원공유가 복잡 → 실행시간 증가

  • 하지만 many-to-many 방식은 나머지 두 모델에 비해 실제로 구현하기가 가장 어렵다.

    또한 대부분의 시스템에서 코어수가 늘어나면서 커널 스레드 개수를 제한할 필요성이 줄었다

    ⇒ 현재 대부분의 시스템에서 one-to-one 모델이 사용되고 있다.

Clone this wiki locally