멀티 스레드 개념
메인(main) 스레드
-
모든 자바 프로그램은 메인 스레드가 main() 메소드 실행하며 시작
-
main() 메소드의 첫 코드부터 아래로 순차적으로 실행
-
실행 조건
-
마지막 코드 실행
-
return 문을 만나면 종료
-
main 스레드는 작업 스레드들을 만들어 병렬로 코드를 실행
-
멀티 스레드 생성해 멀티 태스킹 수행
스레드 종료
싱글 스레드
멀티 스레드
- 실행 중인 스레드가 하나라도 있으면 프로세스 미 종료
멀티 스레드로 실행하는 어플리케이션 개발
- 몇 개의 작업을 병렬로 실행할지 결정하는 것이 선행되어야 함
작업 스레드 생성과 실행
(1) Thread 클래스로부터 직접 생성
- Runnable 인터페이스 사용 (구현)
- Runnable 인터페이스를 매개값으로 갖는 생성자 호출
Thread thread = new Thread(Runnable target);
Runnable 인터페이스
- run() 메소드 하나만 정의되어 있음
- Runnable은 작업 내용을 가지고 있는 객체이지 실제 스레드 아님
- Runnable 구현 생성한 후
- 이것을 매개값으로 해서 Thread 생성자를 호출하면 비로소 작업 스레드 생성
코드 절약하기 위해 Thread 생성자를 호출할 때 Runnable 익명 객체를 매개값으로 사용 가능
작업 스레드는 생성되는 즉시 실행되는 것이 아니라 start() 메소드를 호출해야만 실행
thread.start()
- start() 메소드가 호출되면 작업 스레드는 매개값으로 받은 Runnable run() 메소드를 실행하면서 자신의 작업을 처리
(2) Thread 하위 클래스로부터 생성
- Thread 클래스 상속
- Thread 클래스 상속 수 run 메소드 재정의해서 스레드가 실행할 코드 작성
public class WorkerThread extends Thread
스레드 우선 순위
동시성
- 멀티 작업을 위해 하나의 코어에서 멀티 스레드가 번갈아 가며 실행하는 성질
병렬성
- 멀티 작업을 위해 멀티 코어에서 개별 스레드를 동시에 실행하는 성질
코어
- CPU 칩에서 물리적으로 연산하는 유닛 개수
- 입력된 명령어를 계산하고 해석하는 단위
스레드 스케줄링
- 스레드의 개수가 코어의 수보다 많을 경우
- 스레드를 어떤 순서로 동시성으로 실행할 것인가 결정 -> 스레드 스케줄링
- 스케줄링에 의해 스레드들은 번갈아 가면 run() 메소드를 조금씩 실행
(1) 우선 순위 방식 (코드로 제어 가능)
- 우선 순위가 높은 스레드가 실행 상태를 더 많이 가지도록 스케줄링
thread.setPriority(Thread.MAX_PRIORITY);
thread.setPriority(Thread.MIN_PRIORITY);
(2) 순환 할당 방식 (코드로 제어할 수 없음)
- 시간 할당량(Time Slice)을 정해서 하나의 스레드를 정해진 시간만큼 실행
동기화 메소드와 동기화 블록
- 단 하나의 스레드만 실행할 수 있는 메소드 또는 블록
- 다른 스레드는 메소드 또는 블록이 실행이 끝날 때까지 대기
- 동기화 메소드 : synchronized 키워드 붙임
- 잠금(lock) 의미
- synchronized 키워드
- 인스턴스 메소드와 정적 메소드 다 붙일 수 있음
임계 영역 (critical section)
- 멀티 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역
- 자바에서는 임계 영역을 지정하기 위해 동기화 메소드와 동기화 블록 제공
- 스레드가 객체 내부의 동기화 메소드 또는 블록에 들어가면
- 즉시 객체에 잠금을 걸어 다른 스레드가 임계 영역 코드를 실행하지 못하게 함
동기화 블록
공유 객체를 사용할 때 주의할 점
- 멀티 스레드가 하나의 객체를 공유해서 생기는 오류
스레드 상태
스레드의 일반적인 상태
스레드 클래스에서는 스레드의 상태를 나타내는 열거 상수
실행 상태에서 정지 상태로 갈 수 있는 3가지 상태
- 실행 상태에서 실행 대기 상태로 가지 않고
- 일시 정지 상태로 가기도 함
(1) BLOCKED
-
사용하고자 하는 객체의 락이 풀릴 때까지 기다리는 상태
-
동기화 메소드와 동기화 블록에서
- 한 스레드가 동기화 메소드를 호출하고 있다면 다른 스레드는 이 동기화 메소드 호출 불가 (이때 다른 스레드는 BLOCKED 상태)
-
동기화 메소드를 다 실행하고 난 후 다른 스레드가 BLOCKED 상태가 해제되면서 실행 대기 상태로 되고,
-
다시 실행 상태가 되어 동기화 메소드를 호출할
(2) WAITING 상태
-
다른 스레드가 통지할 때까지 기다리는 상태
-
실행 중에 Object가 가지고 있는 wait() 메소드를 호출하게 되면 스레드는 일시 정지 상태로 가고
-
WAITING된 스레드는 다른 스레드가 notify() 메소드를 호출해야만 실행 대기 상태로 가게 됨
-
WAITING 된 스레드는 자기 스스로 또는 자동으로 실행 대기 상태로 갈 수 없고 다른 스레드가 통지를 해줘야만 실행 대기로 갈 수 있음
-
(다른 스레드가 알려 줘야만 실행 대기 상태로 갈 수 있는 상태)
(3) TIMED_WAITING 상태
- 주어진 시간 동안 기다리는 상태
- sleep(시간) : 주어진 시간 동안 일시 정지 상태
- 주어진 시간이 지나면 자동적으로 실행 대기 상태로 감
TERMINATED 상태 (종료)
- 실행을 마친 상태
- 스레드는 한 번 생성되고 종료되면 더 이상 재사용 불가
- 스레드를 재 실행하려면 항상 새로 생성해서 start() 메소드를 호출하여 실행 대기 상태(RUNNABLE)로 만들어 줘야 함
스레드 상태 제어
- 실행 중인 스레드의 상태를 변경하는 것
- 메소드를 사용하여 상태 변화시킴
- 상태 변화를 가져오는 메소드의 종류
실행 상태에서 호출 가능한 메소드
yield()
- 실행 중인 스레드를 실행 대기 상태로 변경
- 스레드1이 실행 중일 때 스레드1에서 yield() 호출하면 스레드1은 대기 상태로 변경되고
- 스레드1과 동일하거나 높은 우선 순위를 갖는 다른 스레드가 실행 가능
- 무의미한 반복 작업을 수행하는 중에 다른 스레드에게 양보할 때 주로 사용
join()
- 실행 중인 스레드가 일시 정지했다가 join()을 호출한 스레드가 종료되면 실행 대기 상태로 변경
- 실행 중 잠깐 멈추고 기다렸다가 결과 받아서 다시 시작
- 계산 작업을 하는 스레드가 모든 계산 작업을 마쳤을 때, 결과 값을 받아 이용하는 경우 주로 사용