Search

자바의 정석 Chapter 13 : 스레드

프로세스와 스레드
프로세스 : 실행 중인 프로그램, 자원(resource)과 스레드로 구성
스레드 : 프로세스 내에서 실제 작업을 수행. 모든 프로세스는 최소한 하나의 스레드를 갖고 있다
하나의 새로운 프로세스를 생성하는 것보다 하나의 새로운 스레드를 생성하는 것이 더 적은 비용이 든다
멀티스레드의 장단점
장점
시스템 자원을 보다 효율적으로 사용할 수 있다
사용자에 대한 응답성이 향상된다
작업이 분리되어 코드가 간결해진다
단점
동기화에 주의해야 한다
교착상태가 발생하지 않도록 주의해야 한다
각 스레드가 효율적으로 고르게 실행될 수 있게 해야 한다
스레드의 구현과 실행
Thread 클래스를 상속 (Bad! 단일 상속의 한계)
Runnable 인터페이스를 구현 (Better! 다른 클래스 상속 가능)
스레드의 실행 - start()
스레드를 생성한 후에 start()를 호출해야 스레드가 작업을 시작한다
스레드를 시작하면 시작 가능 상태가 되고 OS 스케줄러가 실행 순서를 결정한다
start()와 run()
왜 run()을 만들었는데 start()를 호출하는거지???
→ start()를 통해 새로운 스택을 만들어 run()을 호출하고 start()는 종료된다
main 스레드
main 메서드의 코드를 수행하는 스레드
스레드는 ‘사용자 스레드'와 ‘데몬 스레드' 두 종류가 있다
실행 중인 사용자 스레드가 하나도 없을 때 프로그램은 종료된다
싱글스레드 vs 멀티스레드
시간은 똑같지 않고 OS 스케줄러에 의해 달라진다
스레드의 I/O blocking
스레드의 우선순위
작업의 중요도에 따라 스레드의 우선순위를 다르게 하여 특정 스레드가 더 많은 작업시간을 갖게 할 수 있다
JVM에서의 우선순위는 1~10까지 보통 우선순위는 5이다
Windows OS에서의 우선순위는 32단계로 나눠져 있다
스레드 그룹
서로 관련된 스레드를 그룹으로 묶어서 다루기 위한 것
모든 스레드는 반드시 하나의 스레드 그룹에 포함되어 있어야 한다
스레드 그룹을 지정하지 않고 생성한 스레드는 main 스레드 그룹에 속한다
자신을 생성한 스레드(부모 스레드)의 그룹과 우선순위를 상속 받는다
스레드 그룹의 메서드
데몬 스레드
일반 스레드의 작업을 돕는 보조적인 역할을 수행
일반 스레드가 모두 종료되면 자동적으로 종료된다
가비지 컬렉터, 자동저장, 화면 자동갱신 등에 사용된다
무한루프와 조건문을 이용해서 실행 후 대기하다가 특정조건이 만족되면 작업을 수행하고 다시 대기하도록 작성한다
스레드의 상태
스레드의 실행제어
스레드의 실행을 제어할 수 있는 메서드가 제공된다
sleep()
현재 스레드를 지정된 시간동안 멈추게 한다
예외처리를 해야 한다 (InterruptedException이 발생하면 깨어남)
특정 스데르를 지정해서 멈추게 하는 것은 불가능하다
interrupt()
대기상태(WAITING)인 스레드를 실행대기 상태(RUNNABLE)로 만든다
suspend(), resume(), stop()
스레드의 실행을 일시정지(suspend), 재개(resume), 완전정지(stop) 시킨다
교착상태(dead-lock)에 빠지기 쉬워서 deprecated 되었다
join()
지정된 시간동안 특정 스레드가 작업하는 것을 기다린다
예외처리를 해야한다 (InterruptedException이 발생하면 작업 재개)
yield()
남은 시간을 다음 스레드에게 양보하고 자신(현재 스레드)은 실행대기한다
yield()와 interrupt()를 적절히 사용하면 응답성과 효율을 높일 수 있다
스레드의 동기화(synchronization)
멀티 스레드 프로세스에서는 다른 스레드의 작업에 영향을 미칠 수 있다
진행중인 작업이 다른 스레드에게 간섭받지 않게 하려면 ‘동기화'가 필요
동기화하려면 간섭받지 않아야 하는 문장들을 ‘임계 영역'으로 설정
임계영역은 락(lock)을 얻은 단 하나의 스레드만 출입가능 (객체 1개에 락 1개)
synchronized를 이용한 동기화
synchronized로 임계영역(lock이 걸리는 영역)을 설정하는 방법 2가지
wait()과 notify()
동기화의 단점은 한 번에 한 스레드만 임계 영역에 들어가서 프로그램의 효율이 떨어진다
그 단점을 보완하기 위해 (=동기화의 효율을 높이기 위해) wait(), notify() 사용
Object 클래스에 정의되어 있으며 동기화 블록 내에서만 사용할 수 있다
wait() : 객체의 lock을 풀고 스레드를 해당 객체의 waiting pool에 넣는다
notify() : waiting pool에서 대기 중인 스레드 중의 하나를 깨운다
notifyAll() : waiting pool에서 대기 중인 모든 스레드를 깨운다