반응형
Notice
Recent Posts
Recent Comments
Link
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

지식조각모음

13. 스레드 본문

책/자바의 정석

13. 스레드

y00 2022. 3. 30. 19:06
반응형

process VS thread

  • 프로세스
    • 실행 중인 프로그램
    • 프로그램을 실행하면 OS로부터 실행에 필요한 자원을 할당받아 프로세스가 된다
    • 프로세스 = 데이터 + 메모리 + 스레드
  • 스레드
    • 프로세스의 자원을 이용해서 실제로 작업을 수행하는 것
    • 모든 프로세스는 최소한 하나 이상의 스레드가 존재

멀티스레딩

  • 멀티스레드: 둘 이상의 스레드가 동작
  • 장점
    • CPU 사용률을 향상
    • 자원을 보다 효율적으로 사용
    • 사용자에 대한 응답성 향상
      • 예: 파일을 다운로드 받으면서 채팅하기
      • 한 번에 하나의 작업만 가능했다면 불가능함
    • 작업이 분리되어 코드가 간결
  • 단점
    • 동기화 -> 자원 공유
    • deadlock

스레드의 구현과 실행

구현 방법

  1. Thread 클래스 상속
  2. Runnable 인터페이스 구현
    • 일반적으로 사용

-> 두 작업 모두 추상메서드의 run()의 몸통을 채우는 일

구현 및 실행 예제

1. Thread로 구현

class ThreadExample extends Thread {
    public void run() {
        // 구현
    }
}
  • Thread 클래스를 상속받아 run()을 오버라이딩 한다
public static void main(String[] args){
    ThreadExample thread1 = new ThreadExample();
    thread1.start();

}

2. Runnable로 구현

class RunnableExample implements Runnable {
    public void run() {
        // 구현
    }
}
  • 인터페이스로 구현하였기 때문에 다른 클래스를 상속 받을 수 있다
  • 추상메소드 run()을 구현
public static void main(String[] args){
    Runnable r = new RunnableExample();
    Thread thread = new Thread(r);
    thread.start();
}
  • 다만 start() 클래스가 없기 때문에 Runnable 임터페이스를 구현한 클래스의 인스턴스를 생성 한 다음, Thread클래스의 생성자의 매개변수로 넘겨준다.

실행 - start()

start() 메소드를 호출해야 스레드가 실행된다

  • 실행: start()를 호출해야 (대기상태로 옮긴 뒤 자신의 차례에)스레드가 실행된다
  • 종료: 한 번 실행이 종료된 스레드는 다시 실행할 수 없다

start()와 run()

run()과 start()는 다르다. run()를 호출하는 것은 스레드를 실행시키는 것이 아니라 단순히 클래스에 선언된 메서드를 호출한다. 스레드를 실행시키기 위해서는 start() 메소드를 호출해야 한다.

start()를 호출하면

  1. 새로운 스레드 생성 -> 이때 필요한 call stack 생성
  2. 새로운 call stack에서 run()을 호출해서 run()이 스택의 제일 위로 올라가게 한다.
  3. 호출스택이 2개이므로 순서에 맞게 실행된다

main 스레드

main 메서드의 작업을 수행하는 스레드
프로그램을 실행하기 위해 기본 적으로 하나의 스레드가 필요하고, 그 스레드가 main 메서드를 호출하여 작업을 수행한다.


싱글스레드와 멀티스레드

싱글스레드 프로세스와 멀티스레드 프로세스의 비교

  • 싱글 스레드
    • 한 작업이 끝난 후 다른 작업 시작(t1 -> t2)
  • 멀티 스레드
    • 짧은 시간동안 2개의 스레드를 번걸아가면서 수행 -> 동시에 두 작업이 처리되는 것 같음
    • t1과 t2의 작업 수행 완료시간은 거의 같음
    • 작업전환(context switching)에 시간이 걸리므로 오히려 싱글 스레드보다 작업시간이 더 소요될 수도 있다

소요시간

멀티스레드 일 때 오히려 싱글 스레드보다 작업시간이 더 소요되는 경우가 있다. 그 이유는

  1. context switching
  2. 스레드가 서로 같은 자원을 사용하면 대기시간이 발생한다.
    • 예를 들어 멀티스레드로 화면에 글자를 출력할 때 화면(console)이라는 자원을 두고 두 스레드가 경쟁한다.
    • 그러므로 서로 다른 자원을 사용하는 경우엔 하나의 스레드(t1)에서 idle이 발생하는 경우 다른 스레드(t2)가 작업을 할 수 있어서 효율적이다

우선순위

  • 우선순위: 스레드가 가지고 있는 멤버 변수. 이 값에 따라 스레드가 얻는 실행시간이 달라짐
    • 예 : 사용자에게 빨리 반응해야 하는 작업의 우선순위가 더 높아야 함

특징

  • 범위: 1~10 (main 스레드 우선순위 5)
  • 숫자가 클수록 우선순위가 높다
  • 스레드의 우선순위는 스레드를 생성한 스레드로부터 상속받는다
  • 스레드를 실행하기 전에만 변경할 수 있음

스레드 그룹

  • 스레드 그룹: 스레드를 폴더처럼 묶어서 관리 가능

특징

  • 모든 스레드는 반드시 스레드 그룹에 포함되어야 한다
  • 자신이 속한 그룹 혹은 하위 스레드 그룹만 변경 가능
  • 별도로 그룹지정을 하지 않으면 기본적으로 자신을 생성한 스레드와 같은 그룹에 속한다

자바 어플리케이션이 실행되면, JVM은 main과 system이라는 스레드 그룹을 만든다.

  • main 스레드 그룹
    • main 스레드 속함
  • system 스레드 그룹
    • Finalizer 스레드 속함(GC 수행)

데몬 스레드

일반 스레드의 작업을 돕는 보조적인 스레드. 일반 스레드가 모두 종료되면 데몬 스레드 강제 종료.

  • 예: 가비지 컬렉터, 워드프로세서 자동저장, 화면자동갱신 등

스레드의 상태

상태 설명
NEW 스레드 생성, start() 호출 전
RUNNABLE 실행 중 또는 실행 가능한 상태
BLOCKED 일시정지된 상태
WAITING, TIMED_WAITING 종료는 아니지만 실행가능하지 않은 상태(unrunnable)
TERMINATED 작업 종료
  1. 스레드 생성(NEW)후 start()가 호출되면 실행대기열에 저장되어 차례를 기다린다
    • 실행 대기열: Queue 구조
    • NEW 상태의 스레드가 start()가 호출되면 RUNNABLE로 변경된다
  2. 실행 대기상태에서 실행 상태가 된다
  3. 실행 중에 아래의 특정 상황이 되면 다시 실행 대기 상태가 왼다
    • 주어진 실행시간이 되거나
    • yield()를 만나는 경우
  4. 실행 중에 아래의 특정 상황이 되면 일시정지상태(BLOCKED)가 된다
    • suspend(), sleep(), wait(), join(), I/O block
  5. 4번 상태에서 아래의 특정 상황이 되면 RUNNABLE로 상태가 변경된다
    • 지정된 일시정지시간 만료(time-out)
    • notify(), interrupt() 호출
    • 다시 실행대기열에 저장
  6. 실행을 모두 마치거나 stop()이 호출되면 스레드는 소멸한다(TERMINATED)

스레드 스케줄링

sleep()

지정된 시간동안 스레드를 멈춘다.


try {
    Thread.sleep(1, 500000);
} catch(InterruptedException e) {}

interrupt()

스레드 작업 중지 요청. 요청만 할 뿐 강제종료는 안된다. 단순히 상태를 변경한다.

public class Ex13_9 {
    public static void main(String[] args) {
        ThreadEx9_1 th1 = new ThreadEx9_1();
        th1.start();

        String input = JOptionPane.showInputDialog("아무 값이나 입력하세요");
        System.out.println("입력하신 값은 "  + input + "입니다.");

        th1.interrupt();    // interrupted 상태를 true로 변경한다.
        System.out.println("isInterrupted(): " + th1.isInterrupted());

    }
}


class ThreadEx9_1 extends Thread {
    public void run() {
        int i = 10;

        while (i != 0 && !isInterrupted()) {    // interrupted의 상태가 ture가 되면 while문은 종료된다
            System.out.println(i--);
            for (long x = 0; x < 2500000000L; x++) {

            }
        }
        System.out.println("카운트가 종료되었습니다.");
    }
}

suspend(), resume(), stop()

  • suspend(): sleep()처럼 스레드를 멈추게 한다
    • 교착상태를 일으키기 쉬우므로 사용을 권장하지 않음
    • deprecated 됨
  • resume(): suspend()에 의해 멈춰진 스레드를 다시 실행대기 상태로 변경
  • stop(): 호출 즉시 스레드 종료
    • 교착상태를 일으키기 쉬우므로 사용을 권장하지 않음
    • deprecated 됨

join(), yield()

  • join()
    • 다른 스레드의 작업을 기다림
    • 작업 중에 다른 스레드의 작업이 먼저 수행되어야 할 때 사용
    • interrupt()에 의해 대기상태에서 벗어날수 있음
  • yield()
    • 자신에게 주어진 실행시간을 다른 스레드에게 양보한다

스레드의 동기화(Synchronization)

여러 스레드가 같은 프로세스 내의 자원을 공유하면 서로의 작업에 영향을 주는 경우 발생. 이를 방지하기 위해 임계 영역(critical section)잠금(lock) 개념을 도입.

  • 스레드의 동기화: 한 스레드가 진행 중인 작업을 다른 스레드가 간섭하지 못하도록 막는 것. 각 스레드들이 수행되는 시점을 조절

임계 영역

공유 데이터를 사용하는 코드 영역. 독점을 보장해줘야 하는 영역
각 프로세스는 자신의 임계 구역에 진입하려면 진업허가를 요청해야 함

  1. 입장 구역(entry section)
  2. 임계 구역 진입
  3. 퇴장 구역(exit section)
do {
    wait(mutex); // entry section

    // critical section

    signal(mutext); // exit section

    // 나머지 구역(remainder section)
}
반응형

' > 자바의 정석' 카테고리의 다른 글

15. 입출력  (0) 2022.04.09
14. 람다와 스트림  (2) 2022.04.09
12. 제네릭스, 열거형, 애너테이션  (0) 2022.03.13
Comparator와 Comparable  (1) 2022.03.10
11. 컬렉션 프레임웍  (0) 2022.03.06