github.com/whiteship/live-study/issues/10
목표자바의 멀티쓰레드 프로그래밍에 대해 학습하세요. 학습할 것 (필수)
|
0. 멀티 스레드의 개념
한 개의 프로세스 내부에 여러 스레드가 작업을 처리하는 것.
멀티 스레드는 메인 스레드의 종료 여부와 상관없이 모든 실행중인 스레드가 종료되어야 프로세스를 종료한다.
1. Thread 클래스와 Runnable 인터페이스
작업 스래드 생성 방법
- java.lang.Thread 클래스로부터 직접 객체 생성
- Runnable 매개변수 넣어주어야 함. 이는 인터페이스이기 때문에 구현 객체 생성 후 대입.
- Runnale Interface의 run 메소드가 정의되어 있는데, 이를 재정의하여 작업 스레드가 실행할 코드를 작성해야 함.
- Runnable 매개변수 넣어주어야 함. 이는 인터페이스이기 때문에 구현 객체 생성 후 대입.
Thread thread = new Thread(Runnable target);
- Thread를 상속하여 하위 클래스 만들어 생성
2. 쓰레드의 상태
상태 | 열거 상수 | 설명 |
객체 생성 | NEW | 스레드 객체가 생성, 아직 start() 메소드가 실행되지 않은 상태 |
실행 대기 | RUNNABLE | 실행 상태로 언제든지 갈 수 있는 상태 (스케줄러에게 선택받기 기다리는 상태) |
일시 정지 | WAITING | 다른 스레드가 통지할 때까지 기다리는 상태 |
TIMED_WAITING | 주어진 시간 동안 기다리는 상태 | |
BLOCKED | 사용하고자 하는 객체의 락이 풀릴 때까지 기다리는 상태 | |
종료 | TERMINATED | 실행을 마친 상태(재사용불가) |
- 스레드 상태 제어
메소드 | 설명 |
interrupt() | 일시 정지 상태의 스레드에서 InterruptedException 예외를 발생시켜, 예외 처리 코드 (catch) 에서 실행 대기 상태로 가거나 종료 상태로 갈 수 있도록 한다. |
notify() notifyAll() |
동기화 블록 내에서 wait() 메소드에 의해 정지 상태에 있는 스레드를 실행 대기 상태로 만든다. |
resume() | suspend() 메소드에 의해 일시 정지 상태에 있는 스레드를 실행 대기 상태로 만든다. - Deprecated ( 대신 notify(), notifyAll() 사용) |
sleep(long millis) sleep(long millis, int nanos) |
주어진 시간 동안 스레드를 일시 정지 상태로 만든다. 주어진 시간이 지나면 자동적으로 실행 대기 상태가 된다. |
join() join(long millis) join(long millis, int nanos) |
join() 메소드를 호출한 스레드는 일시 정지 상태가 된다. 실행 대기 상태로 가려면, join() 메소드를 멤버로 가지는 스레드가 종료되거나, 매개값으로 주어진 시간이 지나야 한다. |
wait() wait(long millis) wait(long millis, int nanos) |
동기화(synchronized) 블록 내에서 스레드를 일시 정지 상태로 만든다. 매개값으로 주어진 시간이 지나면 자동적으로 실행 대기 상태가 된다. 시간이 주어지지 않으면 notify(), notifyAll() 메소드에 의해 실행 대기 상태로 갈 수 있다. |
suspend() | 스레드를 일시 정지 상태로 만든다. resume() 메소드를 호출하면 다시 실행 대기 상태가 된다. - Deprecated (대신 wait() 사용) |
yield() | 실행 중에 우선순위가 동일한 다른 스레드에게 실행을 양보하고 실행 대기 상태가 된다. |
stop() | 스레드를 즉시 종료시킨다. - Deprecated |
3. 쓰레드의 우선순위
- 자바의 멀티 스레드는 동시성(멀티 작업을 위해 하나의 코어에서 멀티 스레드가 번갈아가며 실행하는 성질 cf.병렬성과 다름)작업을 바탕으로 작업이 진행되기 때문에, 순서를 정해야만 한다. 이를 스레드 스케줄링이라고 한다.
자바 스레드 스케줄링 방식
- 우선순위(priority) 방식 : 우선순위가 높은 스레드가 실행 상태를 더 많이 가지는 스케줄링 (코드 제어 가능)
- 우선순위는 1~ 10까지 부여 가능 (숫자 클수록 순위 높음)
- default 는 5
- setPriority method 이용
- 순환 할당(round robin) 방식 : 시간 할당량(time slice)을 정해서 하나의 스레드를 저해진 시간만큼 실행하는 스케줄링(코드 제어 불가능)
4. Main 쓰레드
모든 자바 애플리케이션은 main thread가 main() 메소드를 실행하면서 시작한다.
메인 쓰레드는 main() 메소드의 첫 코드부터 아래로 순차적으로 실해라고, main() 메소드의 마지막 코드를 실행하거나 return문을 만나면 종료된다.
메인 스레드는 필요에 따라 작업 스레들르 만들어서 병렬로 코드를 실행한다.
JVM -> main 스레드 생성
main 스레드 -> 작업 스레드들 생성
5. 동기화
스레드가 사용 중인 객체는 작업이 끝날 때까지 타 스레드가 접근하지 못하도록 해야한다. 단 하나의 스레드만이 실행할 수 있는 코드 영역을 임계 영역(critical section)이라고 한다. 이러한 임계 영역을 지정하기 위하여 자바는 동기화 기능을 제공한다.
스레드가 객체 내부의 동기화 메소드 또는 블록에 들어가면, 즉시 객체에 잠금을 걸어 다른 스레드가 임계 영역 코드를 실행하지 못하게 한다.
동기화 메소드 선언 : synchronized 키워드를 붙임 ( 인스턴스 , 정적 메소드 모두 붙이기 가능)
public synchronized void method() {
임계 영역; // 단 하나의 스레드만 실행
}
- 동기화 메소드 : 메소드 전체가 임계 영역이기에 스레드가 동기화 메소드를 실행하는 즉시 객체에 잠금 일어나고 동기화 메소드 실행 종료하면 잠금이 풀림
- 메소드 안에서 일부 내용만 임계 영역으로 지정하고 싶다면 동기화 블록을 이용
public void method() {
// 여러 스레드가 실행 가능한 영역
...
synchronized(공유객체) {
임계영역 // 단 하나의 스레드만 실행
}
}
- 만약 객체에 동기화 메소드와 블록이 여러개 있을 경우, 하나의 동기화 블록이 실행되고 있다면(잠겨있다면) 다른 동기화 블록 및 메소드에도 타 스레드가 접근할 수 없다.
6. 데드락
Tread 1 가 Object A 의 임계영역에 진입을 한 후 임계영역을 탈출하지 않은 상태에서 Object B의 임계영역에 진입하려 한다. 그런데 이때 이미 Thread 1는 Object B의 임계영역에 진입 한 상태가 되어 Thread 1 은 Object B 의 임계역역 시작 지점에서 BLOCKED 된다. 이 상황에서 Object B의 임계영역에 진입한 Thread 2는 Thread 1이 Lock 을 확보한 Object A의 임계 영역을 진입하려 한다. 이 역시 BLOCKED 된다. 양 Thread 는 영원한 BLOCKED 상태에 들어갔다.
출처: https://rightnowdo.tistory.com/entry/JAVA-concurrent-programming-교착상태Dead-Lock [지금 당장 해!!!], 이것이 자바다 (신용권 저)
'Programming > Java' 카테고리의 다른 글
[whiteship 온라인 스터디] 12주차 과제: 애노테이션 (0) | 2021.02.25 |
---|---|
[whiteship 온라인 스터디] 11주차 과제: Enum (0) | 2021.02.24 |
[whiteship 온라인 스터디] 9주차 과제 - 예외처리 (0) | 2021.02.13 |
[whiteship 온라인 스터디] 8주차 과제 - 인터페이스 (0) | 2021.02.13 |
[whiteship 온라인 스터디] 7주차 과제 - 패키지 (0) | 2021.01.02 |