스레드 (thread)
포스트
취소

스레드 (thread)

프로세스(process)란?

  • 단순히 실행 중인 프로그램(program)
  • 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것
  • 프로그램에 사용되는 데이터와 메모리 등의 자원 그리고 스레드로 구성된다.

스레드(thread)란?

  • 프로세스 내에서 실제로 작업을 수행하는 주체
  • 모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행한다.
  • 멀티스레드 프로세스 (multi-threaded process)
    • 두 개 이상의 스레드를 가지는 프로세스

스레드의 생성과 실행

  • Runnable 인터페이스를 구현하는 방법
class ThreadWithRunnable implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()); // 현재 실행 중인 스레드의 이름을 반환
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Thread thread = new Thread(new ThreadWithRunnable()); //Runnable 인터페이스를 구현하는 방법
thread.start(); //스레드의 실행
  • Thread 클래스를 상속받는 방법
class ThreadWithClass extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(getName()); //현재 실행 중인 스레드의 이름을 반환함.
            try {
                Thread.sleep(10); //0.01초간 스레드를 정지 (단위 : 1/1000초)
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

ThreadWithClass thread = new ThreadWithClass(); //Thread 클래스를 상속받는 방법
thread.start(); //스레드의 실행

스레드의 우선순위

  • Java에서 각 스레드는 우선순위(priority)에 관한 자신만의 필드를 가지고 있다.
  • 우선순위에 따라 특정 스레드가 더 많은 시간 동안 작업을 할 수 있도록 설정할 수 있다.
  • getPriority()와 setPriority() 메소드를 통해 스레드의 우선순위를 반환하거나 변경할 수 있다.
  • 스레드의 우선순위가 가질 수 있는 범위
    • 1 ~ 10
    • 숫자가 높을수록 우선순위가 높아진다.
  • 스레드의 우선순위는 비례적인 절댓값이 아닌 어디까지나 상대적인 값이다.
    • 우선순위가 10인 스레드가 우선순위가 1인 스레드보다 10배 더 빨리 수행되는 것이 아니다.
    • 우선순위가 높은 스레드는 우선순위가 낮은 스레드보다 좀 더 많이 실행 큐에 포함되어,
      좀 더 많은 작업 시간을 할당받을 뿐이다.
  • 스레드의 우선순위는 해당 스레드를 생성한 스레드의 우선순위를 상속받게 된다.
  • 기본값 : 5
필드설명
static int MAX_PRIORITY스레드가 가질 수 있는 최대 우선순위를 명시
static int MIN_PRIORITY스레드가 가질 수 있는 최소 우선순위를 명시
static int NORM_PRIORITY스레드가 생성될 때 가지는 기본 우선순위를 명시
  • 사용 예시
class ThreadWithRunnable implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()); // 현재 실행 중인 스레드의 이름을 반환함.
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//s:메인
Thread thread1 = new Thread(new ThreadWithRunnable());
Thread thread2 = new Thread(new ThreadWithRunnable());

thread2.setPriority(10); // Thread-1의 우선순위를 10으로 변경함.

thread1.start(); // Thread-0 실행
thread2.start(); // Thread-1 실행

System.out.println(thread1.getPriority());
System.out.println(thread2.getPriority());
//e:메인

멀티 스레드(multi thread)

  • 멀티 스레드 (multi thread)
    • 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것
  • 멀티 프로세스 (multi process)
    • 여러 개의 CPU를 사용하여 여러 프로세스를 동시에 수행하는 것
  • 공통점
    • 여러 흐름을 동시에 수행한다.
  • 차이점
    • 멀티 프로세스
      • 각 프로세스가 독립적인 메모리를 가지고 별도로 실행된다.
    • 멀티 스레드
      • 각 스레드가 자신이 속한 프로세스의 메모리를 공유한다.

문맥 교환 (context switching)

  • 현재까지의 작업 상태나 다음 작업에 필요한 각종 데이터를 저장하고 읽어오는 작업
  • CPU의 코어 수보다 더 많은 스레드가 실행되면, 각 코어가 정해진 시간동안 여러 작업을 번갈아가며 수행하는데
    이 때 각 스레드가 서로 교체될 때 스레드 간의 문맥 교환이 발생한다.
    • 컴퓨터에서 동시에 처리할 수 있는 최대 작업 수는 CPU의 코어 수와 같다.
  • 문맥 교환에 걸리는 시간이 커지면 커질수록, 멀티 스레딩의 효율은 저하된다.
  • 많은 양의 단순한 계산은 싱글 스레드로 동작하는 것이 더 효율적일 수 있다.
    • 많은 수의 스레드를 실행하는 것이 언제나 좋은 성능을 보이는 것은 아니다.
  • 멀티 스레드는 각 스레드가 자신이 속한 프로세스의 메모리를 공유하므로 시스템 자원의 낭비가 적다.
  • 하나의 스레드가 작업을 할 때 다른 스레드가 별도의 작업을 할 수 있어 사용자와의 응답성도 좋아진다.

스레드 그룹 (thread group)

  • 서로 관련이 있는 스레드를 하나의 그룹으로 묶어 다루기 위한 장치
  • Java에서는 스레드 그룹을 다루기 위해 ThreadGroup이라는 클래스를 제공한다.
  • 스레드 그룹은 다른 스레드 그룹을 포함할 수도 있다.
    • 포함된 스레드 그룹은 트리 형태로 연결된다.
    • 스레드는 자신이 포함된 스레드 그룹이나 그 하위 그룹에는 접근할 수 있지만 다른 그룹에는 접근할 수 없다.
  • 스레드 그룹은 스레드가 접근할 수 있는 범위를 제한하는 보안상으로도 중요한 역할을 하고 있다.
  • 사용 예시
class ThreadWithRunnable implements Runnable {
    public void run() {
        try {
            Thread.sleep(10); //0.01초간 스레드를 멈춤.
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

//s:메인
Thread thread0 = new Thread(new ThreadWithRunnable());
thread0.start(); //Thread-0 실행
System.out.println(thread0.getThreadGroup()); //main이라는 스레드 그룹에 속해있다고 출력된다.

ThreadGroup group = new ThreadGroup("myThread"); //myThread라는 스레드 그룹 생성
group.setMaxPriority(7); //해당 스레드 그룹의 최대 우선순위를 7로 설정

//스레드를 생성할 때 포함될 스레드 그룹을 전달할 수 있다.
Thread thread1 = new Thread(group, new ThreadWithRunnable());
thread1.start(); //Thread-1 실행
System.out.println(thread1.getThreadGroup());
//e:메인

데몬 스레드 (deamon thread)

  • 다른 일반 스레드의 작업을 돕는 보조 스레드
  • 일반 스레드가 모두 종료되면 할 일이 때문에 자동으로 종료된다.
  • 일정 시간마다 자동으로 수행되는 저장 및 화면 갱신 등에 이용된다.
  • 사용 예시
class ThreadWithRunnable implements Runnable {
    public void run() {
        //데몬 스레드인지 확인
        if(Thread.currentThread().isDaemon()){
            while (true) {
                try {
                    Thread.sleep(100L);
                    System.out.println("thread is running (type : daemon)");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        else{
            System.out.println("thread is running (type : normal)");
        }
    }
}

//s:메인
Thread t1 = new Thread(new ThreadWithRunnable());
Thread t2 = new Thread(new ThreadWithRunnable());

t1.setDaemon(true); //t1을 데몬 스레드로 설정

t1.start();
t2.start();
//e:메인

가비지 컬렉터 (gabage collector)

  • 프로그래머가 동적으로 할당한 메모리 중 더 이상 사용하지 않는 영역을 자동으로 찾아내어 해제해 주는 데몬 스레드
  • 데몬 스레드를 이용하는 가장 대표적인 예시
  • Java에서는 프로그래머가 메모리에 직접 접근하지 못하게 하는 대신에 가비지 컬렉터가 자동으로 메모리를 관리해준다.
  • 이용 시 프로그래밍을 하기가 훨씬 쉬워지며, 메모리에 관련된 버그가 발생할 확률도 낮아진다.
  • 동작하는 동안에는 프로세서가 일시적으로 중지되기 때문에 반드시 성능의 저하가 발생합니다.
  • 요즘에는 가비지 컬렉터의 성능이 많이 향상되었다.
  • 새롭게 만들어지는 대부분의 프로그래밍 언어에서 가비지 컬렉터를 제공하고 있다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.