[Day 15 | Java] 프로세스와 스레드 시작

y♡ding·2024년 11월 1일
0

데브코스 TIL

목록 보기
99/163

프로그램

프로그램정적인 코드 집합으로, 주로 파일 형태로 저장됩니다. 예를 들어, 우리가 컴퓨터에 설치한 각종 소프트웨어들이 프로그램입니다. 프로그램은 실행파일이나 소스 코드로 존재하며, 이 자체로는 동작하지 않습니다. 사용자가 실행 명령을 내리면 프로세스가 생성되어 컴퓨터가 프로그램을 실제로 수행하게 됩니다.

프로세스 (Process)

프로세스는 실행 중인 프로그램을 의미하며, 운영 체제는 각 프로세스가 독립적으로 실행될 수 있도록 CPU, 메모리, 디스크와 같은 자원을 할당합니다. 각 프로세스는 독립된 메모리 공간을 가지므로 다른 프로세스와 메모리를 공유하지 않으며, 이러한 분리는 보안성과 안정성을 높입니다.

  • 자원 할당: 프로세스는 연산 자원(CPU, GPU), 메모리(RAM, 디스크), 네트워크 자원을 할당받아 작업을 수행합니다.
  • 종류:
    • Foreground Process: 사용자와 상호작용하는 전면 실행 프로그램으로, UI를 가지고 있습니다.
    • Background Process: UI 없이 백그라운드에서 실행되며 사용자와 직접적인 상호작용이 필요하지 않습니다.
      • 서비스: 시스템 시작과 함께 백그라운드에서 동작하는 특정 작업을 수행하는 프로그램입니다 (예: 데이터베이스 서버).

프로그램이 프로세스로 변환되는 과정

  1. 프로그램 실행 명령: 사용자가 소프트웨어를 실행하거나 자바 애플리케이션을 시작할 때, 운영 체제가 프로그램 파일을 메모리에 적재합니다.
  2. 프로세스 형성: 운영 체제는 프로그램을 메모리에 적재하여 프로세스로 변환하고, CPU 자원을 할당합니다.
  3. 프로세스 실행 및 관리: 프로세스는 운영 체제에 의해 관리되며, CPU 스케줄링에 따라 실행과 대기 상태를 반복하면서 작업을 수행합니다.

스레드 (Thread)

스레드는 프로세스 내에서 실행되는 작은 작업 단위입니다. 스레드는 프로세스의 메모리 공간과 자원을 공유하면서 실행되므로, 하나의 프로세스 내에서 여러 스레드가 동시에 작업을 수행할 수 있습니다. 이를 통해 CPU 사용률을 극대화하고 응답성을 향상시킵니다.

  • 특징:
    • CPU 사용 향상: 여러 스레드가 동시에 실행되므로 CPU 자원을 더 효율적으로 사용합니다.
    • 자원 공유: 스레드 간에 메모리 자원을 공유하여 불필요한 자원 할당을 줄입니다.
    • 응답성 향상: 여러 작업을 동시에 처리함으로써 사용자 요청에 빠르게 응답할 수 있습니다.
    • 코드 간결성: 작업을 분리하여 코드를 간결하게 유지할 수 있습니다.
  • 병렬 처리: 여러 스레드를 사용해 작업을 병렬로 처리합니다. 예를 들어 게임에서 시간을 관리하는 시간 스레드, 총알을 관리하는 총알 스레드, 플레이어 캐릭터를 관리하는 사람 스레드를 각각 실행하여 동시에 작동시킬 수 있습니다.

Thread 생성 방법

Java에서 스레드를 생성하는 방법은 크게 두 가지입니다.

  1. Thread 클래스 상속

    • Thread 클래스를 상속하여 run() 메서드를 재정의합니다.
    • 생성된 Thread 객체에서 start() 메서드를 호출하면 스레드가 실행됩니다.
    public class Go extends Thread {
        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                System.out.println("Go : " + i);
            }
        }
    }
    
  2. Runnable 인터페이스 구현

    • Runnable 인터페이스를 구현하고 run() 메서드를 정의합니다.
    • Runnable 객체를 Thread 생성자에 전달하여 스레드를 생성할 수 있습니다.
    • 이 방식은 객체지향적이며 코드 일관성을 유지하고, 스레드 재사용이 용이합니다.
    public class GoRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                System.out.println("Go : " + i);
            }
        }
    }
    
    public class ThreadMain {
        public static void main(String[] args) {
    				Thread t1 = new Thread(new Go());
            Thread t2 = new Thread(new Come());
            t1.start();
            t2.start();
        }
    }
public class ThreadMain {
    public static void main(String[] args) {
        Go go = new Go();
        Come come = new Come();

        go.start();
        come.start();
    }
}
public class ThreadMain02 {
    public static void main(String[] args) {
        // 익명 내부 클래스로 처리
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 10; i++) {
                    System.out.println("Go : " + i);
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 10; i++) {
                    System.out.println("Come : " + i);
                }
            }
        });

        t1.start();
        t2.start();
    }
}
//람다
public class ThreadMain03 {
    public static void main(String[] args) {
        Thread t1 = new Thread( () -> {
            for (int i = 1; i <= 10; i++) {
                System.out.println("Go : " + i);
            }
        });

        Thread t2 = new Thread( () -> {
            for (int i = 1; i <= 10; i++) {
                System.out.println("Come : " + i);
            }
        });

        t1.start();
        t2.start();
    }
}

Thread의 생명주기 (Lifecycle)

스레드는 생성에서 소멸까지 여러 상태를 거칩니다. 아래는 각 상태의 설명입니다:

  1. NEW: 스레드 객체가 생성된 초기 상태입니다. 아직 start() 메서드가 호출되지 않은 상태입니다.
  2. RUNNABLE: start()가 호출되면 스레드가 실행 대기 상태에 놓입니다. CPU를 할당받으면 실행 상태로 전환됩니다.
  3. RUNNING: CPU를 할당받아 스레드가 실제로 실행 중인 상태입니다.
  4. WAITING: 다른 스레드의 작업을 기다리며 대기하는 상태입니다. join(), wait() 등이 호출될 때 발생합니다.
  5. BLOCKED: I/O 작업이나 락을 기다릴 때 일시적으로 블록된 상태입니다.
  6. TIMED_WAITING: sleep() 등 시간 제한이 있는 대기 상태입니다.
  7. TERMINATED: run() 메서드가 종료되면 스레드는 소멸 상태가 됩니다.

상태 전이

  • yield(): 실행 중인 스레드를 일시적으로 멈추고 다른 스레드에게 CPU를 양보할 때 사용됩니다.
  • sleep(): 일정 시간 동안 스레드를 일시정지합니다.
  • wait()notify(): 스레드 간 동기화에 사용되어, 특정 조건이 충족될 때까지 대기 또는 재개하게 합니다.
  • interrupt(): 다른 스레드에서 해당 스레드를 중단할 때 사용합니다.
  • resume(), join(), stop(): 스레드 실행 상태를 변경하거나 종료하는 데 사용됩니다.

이처럼 Java의 스레드는 생성부터 종료까지 여러 상태를 거치며, 다양한 메서드를 통해 상태 전이와 동기화를 제어할 수 있습니다.


[실습] 단수를 입력 받아서 구구단을 출력하는 스레드 클래스 생성

public class Gugudan extends Thread {

    private int dan;

    public Gugudan(int dan) {
        this.dan = dan;
    }

    @Override
    public void run() {
        for (int i = 1; i < 10; i++) {
            System.out.printf("%s X %s = %s%n", dan, i, (dan * i));
        }
    }
}

package com.test1;

public class GugudanMain {
    public static void main(String[] args) {

        Gugudan gugudan = new Gugudan(3);
        gugudan.start();
    }
}
  • 풀이 위 코드는 스레드를 사용하고 있습니다.. Gugudan 클래스는 Thread를 상속받았고, run() 메서드를 오버라이드하여 스레드의 작업 내용을 정의했기 때문에 Gugudan 객체 자체가 스레드 역할을 합니다. 다음은 코드에서 스레드를 사용하는 방식입니다:
    1. Gugudan 클래스:

      • Thread를 상속하고 run() 메서드를 재정의하였습니다. 이 run() 메서드에는 스레드가 실행할 구구단 출력 작업이 정의되어 있습니다.
    2. GugudanMain 클래스:
      - Gugudan 객체인 gugudan을 생성하고, gugudan.start()를 호출하여 스레드를 시작합니다.

      여기서 중요한 점은 gugudan.start()를 호출하면 스레드가 시작되면서, run() 메서드에 작성된 구구단 출력 작업이 백그라운드에서 실행됩니다. start() 메서드는 새로운 스레드를 생성하고, 그 스레드가 run() 메서드를 실행하도록 합니다.

      만약 gugudan.run()을 직접 호출했다면 단순히 메인 스레드에서 run() 메서드를 실행하는 것이며, 스레드 기능을 사용하지 않는 셈이 됩니다.

public class Gugudan extends Thread {

    private int dan;

    public Gugudan(int dan) {
        this.dan = dan;
    }

    @Override
    public void run() {
        // getName()- 스레드 이름
        System.out.println(this.getName() + "시작");
        for (int i = 1; i < 10; i++) {
            System.out.printf("%s X %s = %s%n", dan, i, (dan * i));
        }
        System.out.println(this.getName() + "끝");
    }
}

public class GugudanMain {
    public static void main(String[] args) {

        Gugudan gugudan1 = new Gugudan(3);
        Gugudan gugudan2 = new Gugudan(6);

        System.out.println("시작");

        // 스레드 이름 정하기
        gugudan1.setName("3단");
        gugudan2.setName("6단");

        gugudan1.start();
        gugudan2.start();

        System.out.println("끝");
    }
}

0개의 댓글

관련 채용 정보