쓰레드

김나영·2023년 7월 12일
0

Java 문법 종합반

목록 보기
21/21

프로세스 Vs 쓰레드

프로세스 vs 쓰레드

  • 프로세스 : 운영체제로부터 자원을 할당받는 작업의 단위
  • 쓰레드 :프로세스가 할당받은 자원을 이용하는 실행의 단위

1. 프로세스

  • 실행 중인 프로그램

ex) 카카오톡, 브라우저, JAVA프로그램

구조

  • OS가 프로그램 실행을 위한 프로세스(resource)를 할당해줄때 프로세스안에 프로그램 Code와 Data 그리고 메모리 영역(Stack, Heap)을 함께 할당해줌

  • Code : Java main 메소드와 같은 코드

  • Data : 프로그램이 실행중 저장 할 수 있는 저장공간

    • 전역변수, 정적변수(static), 배열등 초기화된 데이터를 저장하는 공간
  • Memory (메모리 영역)

    • Stack : 지역변수, 매개변수 리턴 변수를 저장하는 공간
    • Heap : 프로그램이 동적으로 필요한 변수를 저장하는 공간 (new(), mallock())

2. 쓰레드

  • 프로세스내에서 일하는 일꾼(코드실행의 흐름)

생성

  • 프로세스가 작업중인 프로그램에서 실행요청이 들어오면 쓰레드(일꾼)을 만들어 명령을 처리하도록 함

자원

  • 프로세스 안에는 여러 쓰레드(일꾼)들이 있고, 쓰레드들은 실행을 위한 프로세스 내 주소공간이나 메모리공간(Heap)을 공유 받음

  • 추가로, 쓰레드(일꾼)들은 각각 명령처리를 위한 자신만의 메모리공간(Stack)도 할당 받음

Java 쓰레드

  • 일반 쓰레드와 동일하며 JVM 프로세스 안에서 실행되는 쓰레드

  • Java 프로그램을 실행하면 앞서 배운 JVM 프로세스 위에서 실행됨

  • Java 프로그램 쓰레드는 Java Main 쓰레드부터 실행되며 JVM에 의해 실행됨


멀티 쓰레드

Java는 메인 쓰레드가 main() 메서드를 실행시키면서 시작

  • 메인 쓰레드는 필요에 따라서 작업 쓸레드들을 생성해서 병렬로 코드를 실행 시킬 수 있음
  • 즉, Java는 멀티 쓰레드를 지원

1. 단일 쓰레드

  • 프로세스 안에서 하나의 쓰레드만 실행되는 것

  • Java 프로그램의 경우 main() 메서드만 실행시키면 싱글 쓰레드

  • Java 프로그램 main() 메서드의 쓰레드를 메인 쓰레드

  • JVM 의 메인 쓰레드가 종료되면, JVM 도 같이 종료


2. 멀티 쓰레드

  • 프로세스 안에서 여러개의 쓰레드가 실행되는 것

    • 동시다발적, 병렬적으로 실행되는 것
  • 하나의 프로세스는 여러 개의 실행 단위(쓰레드)를 가질 수 있으며 이 쓰레드들은 프로세스의 자원을 공유함

  • Java 프로그램은 메인 쓰레드 외에 다른 작업 쓰레드들을 생성하여 여러 개의 실행 흐름을 만들 수 있음

장점

  • 여러 개의 쓰레드(실행 흐름)을 통해 여러 개의 작업을 동시에 할 수 있어서 성능이 좋아짐
  • 스택을 제외한 모든 영역에서 메모리를 공유하기 때문에 자원을 보다 효율적으로 사용 가능
  • 응답 쓰레드와 작업 쓰레드를 분리하여 빠르게 응답을 줄 수 있음(비동기)

단점

  • 동기화 문제(Synchronization Problem)가 발생할 수 있음

    • 프로세스의 자원을 공유하면서 작업을 처리하기 때문에 자원을 서로 사용하려고 하는 충돌이 발생하는 경우
  • 교착 상태(Deadlock(데드락))이 발생할 수 있음

    • 둘 이상의 쓰레드가 서로의 자원을 원하는 상태가 되었을 때 서로 작업이 종료되기만을 기다리며 작업을 더 이상 진행하지 못하게 되는 상태
  • 병목현상(Bottleneck)이 발생할 수 있음

    • 어떤 시스템 내 데이터의 처리 속도가 지연됨에 의해서 다음에 오는 데이터 처리가 지연되는 현상
    • 비효율적인 알고리즘, 느린 I/O 작업, 과도한 Lock 또는 리소스 제한과 같은 다양한 원인이 있음

쓰레드 구현

Thread

public class TestThread extends Thread{ // Thread 상속
    @Override
    public void run() {
        // 실제 우리가 쓰레드에서 수행할 작업
        for (int i = 0; i < 100; i++) {
            System.out.print("*");
        }
    }
public class Main {
  public static void main(String[] args) {
       TestThread thread = new TestThread(); // Thread 생성
       thread.start(); // Thread 실행
  • Thread 클래스를 상속받아 쓰레드 구현

    • run()을 오버라이딩해서 수행할 작업 작성
  • Thread 객체 생성후 start()로 실행

Runnable Interface

public class TestRunnable implements Runnable { // Runnable 구현
    @Override
    public void run() {
        // Thread에서 수행할 작업 정의!
        for (int i = 0; i < 100; i++) {
            System.out.print("$");
        }
    }
}
public class Main {
    public static void main(String[] args) {
       Runnable run = new TestRunnable(); // Runnable 생성
       Thread thread = new Thread(run); // Thread 생성
       thread.start(); // Thread 실행
  • Runnable 인터페이스를 사용하여 쓰레드 구현

    • run()을 오버라이딩해서 수행할 작업 작성
  • Runnable 구현 객체를 인자로 넣어 Thread 객체 생성 후 start()로 실행

왜 Runnable을 사용하여 쓰레드를 구현할까?

  • Thread는 클래스이므로 다중 상속되지 않아 확장성이 매우 떨어짐
  • 반대로 Runnable은 인터페이스이기 때문에 다른 필요한 클래스를 상속받을 수 있어 확정성에 매우 유리!

람다식

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            int sum = 0;
            for (int i = 0; i < 50; i++) {
                sum += i;
                System.out.println(sum);
            }
            System.out.println(Thread.currentThread().getName() + " 최종 합 : " + sum);
        };
        Thread thread1 = new Thread(task);
        thread1.setName("thread1");
        Thread thread2 = new Thread(task);
        thread2.setName("thread2");
        
        thread1.start();
        thread2.start();
    }
}
  • run() 메서드에 작성했던 쓰레드가 수행할 작업을 실행 블록 { } 안에 작성

  • setName() 메서드 : 쓰레드에 이름을 부여

  • Thread.currentThread().getName() : 현재 실행 중인 쓰레드의 이름을 반환

0개의 댓글