[JAVA] Thread

Thread란?

 

운영체제에서 스레드는 프로세스 내부에서 실행되는 작은 작업 단위이다. 스레드는 프로세스의 실행 흐름을 구성하는 단위로, 하나의 프로세스 내부에 여러개의 스레드가 포함될 수 있다.

 

스레드의 특징

프로세스들이 서로의 데이터에 접근하는것이 직접적으로 불가능한데 반면, 스레드는 프로세스 내부에 존재하기에 프로세스의 데이터 영역에 접근이 가능하다. 그리고 스레드들끼리 서로의 데이터에 접근 가능하다. IPC 필요없이 프로세스의 데이터를 가져올 수 있다.

 

스레드도 일종의 작업 단위라서, 프로세스처럼 작업이 처리된다. 이 말은 즉, 스레드도 프로세스처럼 작업을 병렬로 처리해서 속도를 높일 수 있다는 것이다.

 

스레드는 일종의 함수로 구현된다. 스레드도 함수라서 데이터를 다루고, 데이터를 관리하기 위해 stack 메모리 영역을 가진다. 이 stack 공간은 프로세스가 가지는  stack 메모리 영역과는 별개이며, 스레드의 메모리 영역을 thread stack 이라고 부른다. 프로세스는 메모리 영역을 크게 4가지(code, data, stack, heap)으로 나눌 수 있지만, 스레드는 thread stack 메모리 공간만 갖게된다. 스레드 안에 포함된 데이터(지역 변수)는 thread stack에 저장된다. (단, 프로세스의 stack 영역에는 스레드의 지역변수는 포함하지 않는다.)

 

하나의 프로세스는 내부에 여러개의 스레드를 가질 수 있다.

 

멀티 스레드와 멀티 프로세스 

 

멀티 스레드는 하나의 프로세스 내부에서 여러 개의 스레드가 동시에 실행되는 것이다. 스레드끼리는 서로의 메모리 공간을 공유하고 접근할 수 있다. IPC 통신이 아닌 메모리 기반 통신을 사용하기에 통신속도가 빠르다. 각 스레드들은 여러 자원을 공유하기에, 하나의 스레드에 문제가 생기면 나머지 스레드들도 영향을 받을 수 있다. 프로세스 내에서 스레드의 작업을 여러개로 분할 병렬로 처리할 수 있다.

 

멀티 프로세스는 여러개의 독립적인 프로세스가 동시에 실행되는 것이다. 각 프로세스는 독립된 메모리 공간을 가지며, 서로에게 접근하려면 IPC 기법을 사용해야한다. 각 프로세스는 각각 고유한 자원을 관리하고 있어 서로에게 영향을 미치지 않는다. 하나의 프로세스 작업을 여러개로 분할 병렬로 처리할 수 있다. 이때, 프로세스는 스레드 단위로 작업을 분할한다.

 

스레드의 장점

 

응답성 향상

 

스레드간의 작업분할과 병렬 처리로 인해 사용자가 응용 프로그램을 원할하게 사용하는데 빠른 응답성를 제공할 수 있다.

 

자원공유 효율성 향상

 

스레드는 하나의 프로세스 내에서 실행되기 때문에, 프로세스의 자원을 공유하여 접근할 수 있다. 그리고 스레드는 프로세스 내부에 있기 때문에 별도의 메모리 공간을 할당할 필요없이, 프로세스 내부에서 데이터를 관리하면 된다. 스레드는 프로세스 내부에서 thread stack이라는 공간에 데이터를 관리한다. 따라서 스레드를 사용하면 자원 공유의 효율이 높다.

 

동시성

 

여러 개의 스레드가 동시에 실행될 수 있어서, 작업을 병렬로 처리할 수 있다.

 

간결성

 

작업을 분리할 수 있어서 코드가 간결해질 수 있다.

 

단점

 

스레드 간의 상호간섭

 

멀티 스레드가 실행 중인 상황에, 스레드 간의 상호간섭 문제가 발생할 수 있다. 프로세스는 한 개가 다운되면, 그 프로세스만 작업이 멈추고 다른 프로세스에는 영향이 가지 않는다. 하지만 스레드는 다른 스레드가 작업을 방해하거나, 스레드간의 우선순위 설정에 문제가 있을 경우, 서로에게 영향을 미치기 때문에 예상치 못한 이슈가 발생할 수 있다.

 

성능 저하

 

스레드를 많이 생성하면 성능 저하가 발생할 수 있다. 스레드를 많이 생성하면, 스레드 스케줄러에서 각각의 스레드들이 병렬로 실행되기 위해 컨텍스트 스위칭이 빈번하게 발생해야 하기 때문에 성능 저하가 발생할 수 있다.

 

동기화 이슈

 

여러 스레드가 공유 자원에 동시에 접근할 때, 동기화 문제가 발생할 수 있다. 경쟁상태 문제는 스레드 간의 실행순서나 타이밍에 따라 예측할 수 없는 결과가 발생할 수 있다.

 

자원소비 

 

스레드는 개별적인 실행 흐름을 가지기 때문에, 스레드마다 stack 및 레지스터 등의 메모리 자원을 소비한다. 따라서 스레드의 수가 증가하면 메모리 사용량도 증가하게 되어 시스템 자원이 한계에 도달할 수 있다.

 

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

        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();

        thread1.start();
        thread2.start();
    }

}

 

 

public class Thread1 extends Thread {

    public void run() {
        while(true) {
            System.out.println("thread1");
        }
    }
}

 

public class Thread2 extends Thread {

    public void run() {
        while (true) {


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

 

 

각자 thread1, thread2를 스레드에서 무한히 출력하게 하는 간단한 예제이다. 

실행해보면 동시에 실행하는 것 같지만 사실 거의 동시처럼 실행하게 보일 정도로 빠르게 번갈아가며 실행되고 있다는 것을 알 수 있다.

 

 

이런식으로 extends Thread를 사용하거나 implements Runnable을 사용하고 

public void run()  메서드 안에 스레드에서 실행할 코드를 작성하고 실행하고자 하는 곳에서 해당 객체를 생성해 

start()를 호출하면 된다.  참고로 run()  메서드는 매개변수를 인자로 받을 수 없다.

'Java' 카테고리의 다른 글

Java 객체지향 개념: 추상화, 캡슐화, 상속, 다형성  (0) 2025.02.15
Java Interface의 개념과 활용  (0) 2025.02.15
[JAVA] Servlet Filter란?  (0) 2025.01.15
[JAVA] Kakao Pay Api 사용법  (0) 2025.01.13
[JAVA] Java란 무엇인가  (3) 2025.01.02