자바의 정석 148~157강 ch13 쓰레드
ch 13-1 프로세스와 쓰레드
1. 프로세스 process
실행 중인 프로그램, 자원(메모리, CPU 등)과 쓰레드로 구성
2. 쓰레드 Thread
프로세스 내에서 실제 작업을 수행, 모든 프로세스는 최소한 하나의 쓰레드를 가지고 있음
새로운 프로세스 생성보다 새로운 스레드 생성이 적은 비용
3. 멀티스레드의 장단점
장점 | 단점 |
시스템 자원을 효율적으로 사용 가능 사용자에 대한 응답성 향상 코드 간결 |
동기화 synchronization 주의 교착상태가 발생하지 않도록 주의 각 스레드가 효율적으로 고르게 실행될 수 있게 해야함(기아현상) |
ch 13-3~6 스레드의 구현과 실행
1. 스레드 구현
자바는 단일 상속만 지원, Thread 클래스를 상속받을경우 다른 클래스 상속이 어려워 인터페이스 구현방법이 더 유연
①Thread 클래스 상속
class MyThread extends Thread {
public void run() { } // Thread클래스의 run()을 오버라이딩
}
MyThread t1 = new MyThread(); // 쓰레드 생성
t1.start(); // 실행
②Runnable인터페이스 구현
class MyThread2 implements Runnable {
public void run() { } // Runnable 인터페이스의 추상메서드 run() 구현
}
Runnable r = new MyThread2();
Thread t2 = new Thread(r); // 쓰레드 생성
t2.start(); // 실행
2. 쓰레드 실행 start()
스레드를 생성한 후 start()호출하면 실행 가능 상태
OS 스케줄러가 실행순서를 결정
3. run()과 start()
start() 호출 → 새로운 호출 스택 생성되고 종료
run() 호출 → 새로운 호출스택에서 실행
서로 독립적으로 작업 수행 가능해짐
ch 13-7~13 싱글 스레드와 멀티 스레드, 스레드의 I/O 블락킹
1. main 쓰레드
main 메서드의 코드를 수행하는 쓰레드
사용자 쓰레드와 데몬 쓰레드(보조 쓰레드) 두 종류
실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램 종료
main이 종료되더라도 사용자 쓰레드가 실행 중이면 프로그램 종료되지 않음
2. 싱글 쓰레드
3. 멀티 쓰레드
스레드를 번갈아가며 실행하기 때문에(context switching) 싱글 스레드보다 시간이 조금 더 소요됨
4. 쓰레드의 I/O blocking
입출력시 작업 중단되는 현상
싱글 스레드의 경우 I/O를 기다리는 동안 작업이 정지되지만 멀티 스레드의 경우 I/O를 기다리면서 다른 스레드가 작업을 실행한다.
ch 13-14~17 쓰레드의 우선순위, 쓰레드 그룹
1. 쓰레드의 우선순위
작업의 중요도에 따라 쓰레드의 우선순위를 다르게 하여 특정 쓰레드가 더 많은 작업 시간을 갖게 할 수 있음
1~10까지 설정 가능, 기본 우선순위는 5
우선순위는 희망사항일 뿐 OS 스케줄러가 알아서 조정
2. 쓰레드 그룹
서로 관련된 쓰레드를 그룹으로 묶어서 다루기 위함
모든 쓰레드는 하나의 쓰레드 그룹에 포함, 미지정시 main쓰레드 그룹에 속함
자신을 생성한 쓰레드(부모쓰레드)의 그룹과 우선순위를 상속 받음
ch 13-18~21 데몬 쓰레드, 쓰레드의 상태
1. 데몬 쓰레드
인반 쓰레드의 작업을 돕는 보조적인 역할 수행
일반 쓰레드가 모두 종료되면 자동으로 종료
가비지 컬렉터, 자동 저장, 화면 자동 갱신 등에 사용
무한루프와 조건문을 이용해 실행 후 대기하다가 특정 조건이 만족되면 작업을 수행하고 다시 대기하도록 작성
class Ex13_7 implements Runnable {
static boolean autoSave = false;
public static void main(String[] args) {
Thread t = new Thread(new Ex13_7());
t.setDaemon(true); // start()전에 설정
// 데몬으로 지정하지 않으면 종료되지 않는다.
t.start();
for(int i=1; i <= 10; i++) {
try{
Thread.sleep(1000);
} catch(InterruptedException e) {}
System.out.println(i);
if(i==5) autoSave = true;
}
System.out.println("프로그램을 종료합니다.");
} // main 쓰레드
// 실행 중인 일반 쓰레드가 없으면 데몬쓰레드도 종료
public void run() {
while(true) { // 무한루프
try {
Thread.sleep(3 * 1000); // 3초마다
} catch(InterruptedException e) {}
// autoSave의 값이 true면 autoSave()를 호출
if(autoSave) autoSave();
}
}
public void autoSave() {
System.out.println("작업파일이 자동저장 되었습니다.");
}
}
2. 쓰레드 상태
NEW | 쓰레드가 생성되고 start() 미호출 상태 |
RUNNABLE | 실행 중 또는 실행 가능한 상태 |
BLOCKED | 동기화 블럭에 의해서 일시정지된 상태(lock이 풀릴 때까지 기다리는 상태) |
WAITING TIMED_WAITING |
쓰레드의 작업이 종료되지 않았지만 실행가능하지 않는 일시정지 상태 TIMED_WAITING 일시정지 시간 지정 |
TERMINATED | 쓰레드의 작업 종료 |
3. 쓰레드의 실행 제어
실행을 제어할 수 있는 메서드 제공
static void sleep(long millis) static void sleep(long millis, int nanos) |
지정된 시간동안 쓰레드 일시정지, 지정 시간이 지나면 자동으로 실행대기 상태 쓰레드 자기 자신에게만 호출 가능 |
void join() void join(long millis) void join(long millis, int nanos) |
지정된 시간동안 쓰레드 실행, 지정 시간이 지나거나 작업이 종료되면 join()을 호출한 쓰레드로 다시 돌아와 실행함 |
void interrupt() | sleep()이나 join()에 의해 일시정지상태인 쓰레드를 깨워 실행대기 상태로 변경 Interrupt Exception 발생하여 일시정지 상태 벗어남 |
void stop() | 쓰레드 즉시 종료 |
void suspend() | 쓰레드 일시정지, resume() 호출시 다시 실행대기상태로 변함 |
void resume() | suspend()에 의해 일지정시상태에 있는 쓰레드 실행대기상태로 변환 |
static void yield() | 실행 중 자기에게 주어진 실행시간을 다른 쓰레드에게 양보하고 자신은 실행대기상태 쓰레드 자기 자신에게만 호출가능 |
ch 13-22~25 sleep(), interrupt()
1. sleep()
현재 쓰레드를 지정된 시간동안 멈추게 함
자기 자신에게만 호출 가능한 메서드 → 특정 쓰레드 지정해 멈추게하는 것 불가능
시간이 종료되거나 intrrupt()메서드 호출하면 실행대기 상태로 변경
실행대기 상태로 변경될 때 예외가 발생되는 메서드 → InterruptException 예외 처리 필요
2. interrupt()
대기상태WAITING인 쓰레드를 실행대기RUNNABLE 상태로 만듦
inturrpt() | interrupted 상태를 false → true |
isInterrupted() | interrupted 상태 반환 |
interrupted() | isInterrupted() + false로 초기화 |
ch 13-26~27 suspend(), resume(), stop()
suspend() 쓰레드 일시정지
resume() suspend()에 의해 일시정지된 쓰레드를 실행대기 상태로 만듦
stop() 쓰레드 즉시 종료
교착상태 가능성↑ deprecated 되었음
ch 13-28~29 join(), yield()
1. join()
지정 시간동안 특정 쓰레드가 작업하는 것을 기다림
예외가 발생되는 메서드 → InterruptException 예외 처리 필요
2. yield()
남은 시간을 다음 쓰레드에게 양보하고 자신은 실행대기 상태로 변경
자기 자신에게만 호출 가능한 메서드
yield()와 interrupt()를 적절히 사용하면 응답성과 효율을 높일 수 있음 → busy-waiting을 줄일 수 있음
ch 13-30~33 쓰레드의 동기화
1. 쓰레드의 동기화
멀티 쓰레드 프로세스에서 다른 쓰레드의 작업에 영향 미칠 수 있음
진행중인 작업이 다른 쓰레드에게 간섭받지 않게 하려면 동기화 필요
임계영역 : 간섭받지 않아야 하는 문장을 설정, 락을 얻은 단 하나의 쓰레드만 출입가능(1객체 락 1개)
2. synchronized로 임계영역 설정하는 방법
① 메서드 전체 임계영역으로 지정
public synchronized void calcSum() { }
② 특정 영역 임계영역으로 지정
synchronized(객체 참조변수) { }
ch 13-34~36 wait(), notify()
동기화 효율을 높이기 위해 wait(), notify() 사용
Object 클래스에 정의, 동기화 블록 내에서만 사용 가능
wait() | 객체의 lock을 풀고 쓰레드를 해당 객체의 waiting pool에 넣음 |
notify() | waiting pool에서 대기중인 쓰레드 중 하나 깨움 |
notifyAll() | waiting pool에서 대기중인 모든 쓰레드 깨움 |