JAVA/[JAVA] 예외 처리와 스레드

스레드

보배 진 2021. 9. 26. 00:20

프로세스 : 실행 중인 하나의 프로그램

하나의 프로그램이 다중의 프로세스를 만들기도 한다


스레드 개요

멀티태스킹, 컴퓨터가 여러개의 일을 동시에 처리하는 것

(두 가지 이상의 작업을 동시에 처리)

이와 같은 멀티태스킹을 구현하기 위해 운영체제는

멀티프로세싱을 시스템을 지원해야 한다.

 

멀티 프로세스, 독립적으로 프로그램들을 실행하고 

여러 가지 작업을 처리하는 것

 

멀티프로세스 시스템은 여러개의 프로세스가

한 컴퓨터 안에서 동시에 수행되는 것을 지원하지만

하나의 프로그램이 동시에 여러가지 일을 하는 것은 지원하지 않는다.

 

 [ 설명 : 한 컴퓨터 안에서  "실행 중인 프로그램(프로세스)" 여러개를 동시에 수행되는 것은 지원하지만

하나의 프로그램이 동시에 여러가지 일을 수행하는 것은 지원하지 않는다 ]

 

멀티스레드, 하나의 프로그램 안에서 여러가지 일을 동시에 수행하는 것

스레드 : 어떠한 프로그램 내에서 특히 프로세스 내에서 실행되는 흐름의 단위

 

일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만,

프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다.

 

멀티 프로세스는 독립적으로 프로그램들을 실행하고 여러가지 작업 처리    멀티 스레드 한 개의 프로그램을 실행하고 내부적으로 여러 가지 작업 처리 (사진 출처 : 이것이 자바다)

 

멀티스레드가 지원되면

- 하나의 프로그램이 동시에 여러 작업을 수행할 수 있다

- 스레드 간에 데이터가 공유 가능하므로 멀티 프로세스 시스템보다 효율적으로 프로그램을 작성할 수 있다

- 자바는 언어 차원에서 스레드를 지원되므로 프로그래머가 이전보다 쉽게 멀티스레드 구현이 가능하다

- 안전성과 효율성을 보장할 수 있다

- 자바에서 main()도 하나의 스레드이다


메인(main) 스레드

모든 자바 프로그램은 메인 스레드가 main() 메소드를 실행하며 시작

main() 메소드의 첫 코드부터 아래로 순차적으로 실행

 

실행 종료 조건

- 마지막 코드 실행

- return 문을 만나면

 

 

main 스레드는 작업 스레드들을 만들어 병렬로 코드를 실행한다

: 멀티 스레드를 생성해 멀티 태스킹 수행

 

 

프로세스의 종료

- 싱글 스레드 : 메인 스레드가 종료하면 프로세스도 종료

- 멀티 스레드 : 실행 중인 스레드가 하나라도 있다면, 프로세스 미종료

 

 

 

멀티 태스킹과 멀티 스레드의

공통점

아주 짧은 시간 간격을 두고 여러 개의 프로세스를 번갈아 실행됨으로써

동시에 여러 개의 프로세스가 실행되는 것처럼 보이게 한다

 

차이점

멀티 태스킹은 동시에 여러 개의 프로그램을 실행시키는 것이고,

멀티 스레드는 하나의 프로그램을 여러 개의 기능으로 나누어 이를 동시에 실행시킨다


멀티스레드 프로그램

멀티스레드 프로그램 작성을 위해

java.lang.Thread 클래스를 사용하는 방법과

java.lang.Runnable 인터페이스를 사용하는 방법을 제공한다.


Thread 클래스를 상속하는 방법

스레드 기능을 하는 클래스를 만들기 위해서

클래스 Thread를 상속받아 만든다.

run() 메소드를 구현한다

run() 메소드 : 스레드의 실행 주체가 되는 메소드로 스레드의 주요 기능 기술

 

멀티스레드 프로그램 작성 방법 1

1) 스레드 클래스 생성 : Thread 클래스 상속, 스레드 기능 구현 : run() 구현

2) 스레드 객체 생성 : new 연산자

3) 스레드 실행 : start() 메소드 호출

 

- 구문

public class 스레드 클래스 이름 extends Thread {

      public void run(){

            // 처리 내용

      }

}

 

스레드 실행 과정

- start() 메소드를 호출하면

  • JVM이 해당 스레드를 준비 상태(Ready)로 변경
  • JVM 스케줄러에 의해 실행 상태(Run)로 변경
  • run() 실행

- 프로그래머가 직접 run() 메소드를 호출하면, 스레드로 동작하지 않는다


Runnable 인터페이스를 구현하는 방법

Runnable 인터페이스를 상속받고 추상 메소드인 run() 메소드를 수현한다.

(스레드 기능을 하는 클래스를 만들기 위해 클래스 Thead를 상속받지 않는 방법)

Runnable 인터페이스를 구현하여 만든 클래스는 Thread가 아니기 때문에

Thread 클래스로 객체 생성 불가능

스레드 생성자의 인자로 사용하여 스레드를 생성한 후

start() 메소드를 호출해야 한다.

 

멀티스레드 프로그램 작성 방법 2

1) 스레드 클래스 생성 : Runnable 인터페이스 구현, 스레드 기능 구현 : run() 구현

2) 스레드 객체 생성 : new 연산자 (Thread 클래스로 생성한 객체가 아닙니다)

3) 스레드 실행 : start() 메소드 호출

 

- 구문

public class 클래스 이름 implements Runnable {

      public void run() {

            // 처리 내용

      }

}

 

Thread 클래스를 상속하는 방법과 Runnable 인터페이스를 구현하는 방법에 큰 차이는 없다

 

Thread 클래스를 상속하는 경우 Thread 클래스의

모든 메소드를 상속받아 사용할 수 있다

 

Runnable 인터페이스를 구현하는 이유 

자바는 단일 상속만 지원하기에 스레드를 구현하고자

하는 클래스가 다른 클래스를 상속받았을 경우

 Thread 클래스를 상속할 수 없기 때문이다.

(이전 클래스가 이미 상속을 받은 상태라면 Thread를 또 상속할 수 없다)

 

extends implements
부모에서 선언
정의를 모두 하며 자식은 메소드
변수를 그대로 사용할 수 있다
부모 객체는 선언만 하며 정의(내용)은
자식에게서 오버라이딩(재정의) 해서 사용해야 한다

 

 

 


스레드의 상태

스레드의 상태에는

- start 상태

- Runnable 상태

- Run 상태

- NotRunnable 상태

- Dead 상태


- start 상태는 시작 상태, start() 메소드를 호출했을 때의 상태이고 바로 Runnable 상태로 변한다

- Runnable 상태는 동작할 수 없는 상태, 스레드가 실행되면 보통 Runnable 상태가 되고

Runnable 상태의 스레드는 여러개가 존재할 수 있다

- Run 상태는 동작 상태로, Runnable 상태에서만 Run 상태가 될 수 있고 한 순간 단 하나의 스레드만이 Run 상태가 됨

- NotRunnable 상태는 대기 상태로, Run 상태로 진입할 수는 없고 대기 상태를 말한다 (Dead 상태는 아님)

- Dead 상태는 종료 상태로, run() 메소드의 종료는 스레드의 종료를 의미

 

 

Runnable 상태와 Run 상태 간의 변화는 스케줄러에 의해 계속 변화하는데

Runnable 상태에 있는 스레드들끼리 번갈아 가면서 Run 상태가 되고

Run 상태가 된 스레드는 작업을 진행할 수 있다.

 

 

 

sleep(시간) 메소드

일정 시간 동안 NotRunnable 상태가 됨,

일정 시간이 지나면 다시 Runnable 상태가 된다

시간 단위는 1/1000초

 

 

wait() 메소드

wait()를 만나면 NotRunnable 상태가 되고

다시 notify() 메소드를 만나면 Runnable 상태가 된다

 


스레드의 우선순위

우선순위는 어떤 스레드를 더 먼저 실행할 수 있는 권한을

주느냐의 문제로 보통 스케줄러가 여러 메소드 중에서 우선순위가

높은 스레드를 실행할 수 있도록한다

 

 

우선 순위 방식

스레드의 우선순위는 프로그램으로 지정가능하다

우선순위는 1 낮음 부터 10 높음까지로 보며

모든 스레드는 기본적으로 5의 우선순위를 할당

 

우선권 상수

- public static final int MAX_PRIORITY : 가장 높다, 10

- public static final int MIN_PRIORITY : 가장 낮다, 1

- public static final int NORM_PRIORITY : 중간, 5

 

메소드

- public final int getPriority() : 우선순위를 얼어오는 메소드

- public final void setPriority(int newPriority) : 우선순위를 지정하는 메소드

- public final void setName(String name) : 스레드 이름 지정하는 메소드

- public final String getName() : 스레드 이름 얻어오는 메소드


순환 할당 방식(코드로 제어 불가능)

시간 할당량(Time Slice)을 정해서 하나의 스레드를 정해진

시간만큼 실행하고 다시 다른 스레드를 실행하는 방식입니다.


스레드의 동기화

동기화는 하나의 스레드가 끝날 때까지 락(lock)을 걸어서

다른 스레드가 동일한 데이터를 갱신하지 못하도록 하는 것

 

하나의 자원을 한 시점에서 하나의 스레드만이 사용하도록 하는 것

 

스레드를 동기화 시키기 위해서 synchronized 키워드를 사용

synchronized로 동기화된 메소드는 락을 설정하여 완료될 때까지 유지하며

동시에 호출 불가능하다

 

스레드 동기화 방법

- 메소드 전체를 동기화

  동기화 하려는 메소드 이름 앞에 synchronized를 추가한다

 : 접근 제한자 synchronized 반환형 이름(인자) { 실행 코드 }

 

- 특정 블록을 지정항 객체를 동기화

  동기화하려는 메소드 내에 synchronized(this){ } 블록을 추가한다.

 : synchronized(객체 변수){ 실행 코드 }


스레드에 일시 정지 상태를 도입한 경우

상태 열거 상수 설명
객체 생성 NEW 스레드 객체가 생성, 아직 staart() 메소드가 호출되지 않은 상태
실행 대시 RUNNABLE 실행 상태로 언제든지 갈 수 있는 상태
일시 정지 BLOCKED 사용코저하는 객체의 락이 풀릴 때까지 기다리는 상태
WATITING 다른 스레드가 통지할 때까지 기다리는 상태
TIMED_WAITING 주어진 시간 동안 기다리는 상태
종료 TERMINATED 실행을 마친 상태

 

상태 제어 : 실행 중인 스레드의 상태를 변경하는 것

 

주어진 시간 동안 일시 정지 : sleep()

얼마 동안 일시 정지 상태로 있을 것인지 밀리 세컨드(1/1000) 단위로 지정

일시정지 상태에서 interrupt() 메소드 호출 -> InterruptedException 발생

 

다른 스레드에게 실행 양보 : yield()

다른 스레드의 종료를 기다림 : join()


스레드간 협업 : wait(), notify(), notifyAll()

 

동기화 메소드 또는 블록에서만 호출 가능한 Object의 메소드

 

- wait() : 호출한 스레드는 일시정지가 된다.

다른 스레드가 notify() 또는 notifyAll()을 호출하면

실행 대기 상태가 된다

 

- wait(long timeout)

- wait(long timeout, Int nanos) : notify()가 호출되지 않아도

시간이 지나면 스레드가 자동적으로 실행 대기 상태가 된다


스레드의 안전한 종료 : stop 플래그, interrupt()

: 경우에 따라 실행 중인 스레드를 즉시 종료해야 할 필요 있을 때 사용

 

stop() 메소드
- 스레드 즉시 종료 되는 편리함
- Deprecated - 사용 중이던 자원들이 불안전한 상태로 남겨짐

 

 interrupt() 메소드
- 스레드가 일시 정지 상태일 경우 InterruptedException 발생 시킴
- 실행대기 또는 실행상태에서는 InterruptedException 발생하지 않음
- 일시 정지 상태로 만들지 않고 while문 빠져 나오는 방법으로도 쓰임


데몬(daemon) 스레드
- 주 스레드의 작업 돕는 보조적인 역할 수행하는 스레드
- 주 스레드가 종료되면 데몬 스레드는 강제적으로 자동 종료

( 주 스레드의 보조 역할을 수행이던 데몬 스레드는 주 스레드가 종료되면 존재 의미가 없어지기 때문이다 )

 

스레드를 데몬 스레드로 만들기
- 주 스레드가 데몬이 될 스레드의 setDaemon(true) 호출
- 반드시 start() 메소드 호출 전에 setDaemon(true) 호출 : 그렇지 않으면 IllegalThreadStateException이 발생

 

현재 실행중인 스레드가 데몬 스레드인지 구별 : isDaemon() 메소드의 리턴값이 true면 데몬 스레드

'JAVA > [JAVA] 예외 처리와 스레드' 카테고리의 다른 글

예외 처리  (0) 2021.09.25