Java Thread에 대한 이해

박현우·2024년 1월 10일

1. Thread
1-1. 프로세스(process)

  • 운영체제에서는 실행 중인 하나의 애플리케이션을 프로세스라고 한다.
  • 사용자가 애플리케이션을 실행하면 운영체제로부터 실행에 필요한 메모리를 할당받아 애플리케이션의 코드를 실행하는데 이것이 프로세스이다.
  • 자원(resources)과 스레드로 구성

1-2. Thread란?

  • 하나의 프로세스 내부에서 독립적으로 실행되는 하나의 작업단위를 말하며, 세부적으로는 운영체제에 의해 관리되는 하나의 작업 혹은 테스크를 의미한다.

  • 하나의 실행 흐름, 프로세스 내부에 존재

  • main() 실행문은 하나의 스레드

  • 이외의 또다른 스레드를 만들려면 Thread 클래스를 상속하거나, Runnable 인터페이스를 구현해야 한다.

  • 하나의 스레드는 하나의 코드 실행 흐름이기 때문에, 한 프로세스 ㅐ에 스레드가 2개라면 2개의 코드 실행 흐름이 생긴다는 의미다.

    	프로세스 : 스레드 = 공장 : 일꾼
  • 싱글 스레드 프로세스 : 자원 + 일꾼(스레드)

  • 멀티 스레드 프로세스 : 자원 + 일꾼(스레드) + 일꾼(스레드) + ...

1-3. 멀티 프로세스 vs 멀티 스레드

  • 하나의 새로운 프로세스를 생성하는 것보다 하나의 새로운 스레드를 생성하는 것이 더 적은 비용이 든다.

1-4. 멀티 스레드의 장단점

  • 장점
    -> 자원을 보다 효율적으로 사용할 수 있다.
    -> 사용자에 대한 응답성이 향상이 된다.
    -> 작업이 분리되어 코드가 간결해진다.

  • 단점
    -> 동기화에 주의해야 한다.
    -> 교착상태(dead-lock)가 발생하지 않도록 주의해야 한다.
    -> 각 스레드가 효율적이고 고르게 실행될 수 있게 해야 한다.

1-5. Thread 생성 주기

  • New -> Runnable -> Running -> Dead
    start() run()

  • New : 스레드가 생성되었지만 스레드가 아직 실행 준비가 되지 않은 단계

  • Runnable : 스레드가 실행되기 위한 준비 단계

  • Running : 선택된 스레드가 실행되는 단계

  • Blocked : 스레드가 작업을 완수하지 못하고 잠시 작업을 멈추는 단계

1-6 Runnable(준비 상태)

  • 스레드가 실행되기 위한 준비단계이다. CPU를 점유하고 있지 않으며 실행(Running)을 하기 위해 대기하고 있는 상태이다. Ready 준비 상태라고 한다.

1-7. Running(실행 상태)

  • CPU를 점유하고 실행하고 있는 상태이며, run() 메서드가 호출된 상태이다.
  • Runnable(준비 상태)에 있는 여러 스레드 중 우선 순위를 가진 스레드가 결정되면 JVM이 자동으로 run() 메서드를 호출하여 스레드가 Running 상태로 진입한다.

1-8. Thread의 run()과 start()의 차이

  • start()
    -> Thread가 생성되며, Thread가 시작되면 run() 메서드가 실행
    -> 멀티스레드로 동작한다.

  • run()
    -> Thread가 생성되지 않으며, 그냥 run() 메서드만 실행
    -> 싱글스레드로 동작한다.

      package thread;
    
    	public class Main03 {
    
    	public static void main(String[] args) {
    		// Runnable 인터페이스 객체 생성과
    		// 객체를 매개변수로 하여 스레드 객체 한번에 생성
    		Thread th1 = new Thread(new RunnableTest());
    		Thread th2 = new Thread(new RunnableTest());
    	
    		// 동시에 똑같은 숫자가 나온다.
    	//		th1.start();
    	//		th2.start();
    	
    		// 번갈아가면서 나옴
    		th1.run();
    		th2.run();
    	
    	}
    
    	}

1-9. Thread 종료

  • Thread의 interrupt() 메서드는 스레드가 일시 정지 상태에 있을 때 interruptedException 예외를 발생시키는 역할을 한다.

  • 이것을 이용하면 Thread의 run() 메서드를 정상 종료시킬 수 있다.

    	package thread;
    
    	public class ThreadInterruptTest extends Thread {
    
    	@Override
    	public void run() {
    		try {
    			for(int i=0; i<= 10; i++) {
    				Thread.sleep(1000);
    				System.out.println(Thread.currentThread().getName()+ " " + i + " 번째 수행");
    			}
    		
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    			System.out.println("스레드 종료");
    			// 스레드 함수 내에서 return 문을 통해서
    			// 종료 및 소멸시키는 방법이 가장 이상적
    			return;
    		}
    		}
    		}
    	
  •    package thread;
    
    	public class Main04 {
    
    	public static void main(String[] args) {
    		ThreadInterruptTest th = new ThreadInterruptTest();
    		th.start();
    	
    		// 3초 후에 인터럽트
    		try {
    			Thread.sleep(3000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		th.interrupt();
    	}
    
    	}

1-10. 멀티 스레드 주의사항

  • 멀티스레드가 동시에 수행되면서 공유될 수 있을 때, 공유되는 부분은 상호 배타적으로 사용돼야 한다.

  • DeadLock 문제
    -> 멀티스레드를 사용할 때 주의할 점 중의 하나로 프로그램에서 스레드를 잘못 만들면 프로그램의 수행이 이루어지지 않고 무한 수행하는 DeadLock을 만들 수 있다.

  • 임계영역
    -> 공유 자원을 사용하는 코드 영역을 임계영역이라고 한다.
    -> 이 부분에서는 공유 자원을 동시에 수정할 수 없도록 상호 배타적으로 실행될 수 있도록 작성되어야 한다.

  • 자바에서 상호배제 문제를 해결하는 방법
    -> 자바는 한 순간에 하나의 스레드만 실행할 수 있는 synchronized method 제공
    -> 공유 자원을 사용하는 영역을 synchronized(객체명)의 블록으로 지정

0개의 댓글