하나의 프로그램이 여러개의 작업을 동시에 처리
사례
스레드 개념과 실
테트리스 프로그램을 구성하는 멀티스레드 분석
스레드
- 사용자가 작성한 코드로서, JVM에 의해 스케줄링되어 실행되는 단위
자바의 멀티태스킹
- 멀티스레딩만 가능
- 스레드는 JVM의 의한 실행 단위, 스케쥴링 단위
- 하나의 응용프로그램은 여러 개의 스레드로 구성 가능
멀티스레딩의 효과
- 한 스레드가 대기하는 동안 다른 스레드는 실행
- 프로그램 전체적으로 시간 지연을 줄임
웹 서버의 멀티스레딩 사례
자바 스레드
- 자바 가상 기계에 의해 스케쥴되는 실행 단위의 코드 블럭
- 스레드의 생명 주기는 JVM에 의해 관리됨
- JVM은 스레드 단위로 스케쥴링
- JVM과 멀티스레드의 관계
- 하나의 JVM은 하나의 자바 응용프로그램만 실행
- 자바 응용프로그램이 시작할 때 JVM이 함께 실행됨
- 종료 하면 함께 종료함
- 하나의 응용프로그램은 하나 이상의 스레드로 구성 가능
JVM과 자바 응용프로그램, 스레드의 관계
자바 스레드와 JVM
스레드 클래스, 코드 작성
class TimerThread extends Thread { .................................................... @Override public void run() { // run() 오버라이딩 ......................... } }
- run() method 오버라이딩
- run() method : thread code
- run() method에서 스레드 실행 시작
스레드 객체 생성
TimerThread th = new TimerThread();
스레드 시작
th.start();
- start() method 호출
- 스레드로 작동 시작, JVM에 의해 스케쥴 되기 시작
Thread를 상속받아 1초 단위로 초 시간을 출력하는 TimerThread 작성
예제 13-1 : Thread를 상속받아 1초 단위의 타이머 만들기
스레드 만들 시 주의 사항
- run() method가 종료하면 스레드는 종료
- 스레드 계속 살아있게 하려면 run() method 내 무한루프 작성
- 한번 종료한 스레드는 다시 시작시킬 수 없다.
- 다시 스레드 객체 생성 하고 start()호출해야 함.
- 한 스레드에서 다른 스레드를 강제 종료할 수 있다.
스레드 클래스, 코드 작성
class TimerThread implements Runnable { .................................................... @Override public void run() { // run() 오버라이딩 ......................... } }
- run() method 오버라이딩
- run() method : thread code
- run() method에서 스레드 실행 시작
스레드 객체 생성
TimerThread th = new TimerThread();
스레드 시작
th.start();
Runnable 인터페이스를 상속받아 1초 단위로 초 시간을 출력하는 스레드 작성
예제 13-2 : Runnable 인터페이스를 이용하여 1초 단위로 출력하는 타이머 스레드 만들기
예제 13-3 : 깜박이는 문자열을 가진 레이블 만 들기
스레드 상태 6가지
NEW
- 스레드가 생성되었지만 스레드가 아직 실행할 준비가 되지 않았음
RUNNABLE
- 스레드가 현재 실행되고 있거나 실행 준비되어 스케쥴링을 기다리는 상태
WAITING
- wait()를 호출한 상태(다른 슽레드가 notify() or notifyAll()을 불러주기를 기다리고 있는 상태)
- 스레드 동기화를 위해 사용
TIMED_WAITING
- sleep(n)을 호출하여 n 밀리초 동안 잠을 자고 있는 상태
BLOCK
- 스레드가 I/O 작업을 요청하면 JVM이 자동으로 BLOCK상태로 만듦
TERMINATED
- 스레드가 종료한 상태
=> 매우 중요 암기!!
스레드 우선 순위
- 최대값 = 10(MAX_PRIORITY)
- 최소값 = 1(MIN_PRIORITY)
- 보통값 = 5(NORMAL_PRIORITY)
스레드 우선순위는 응용프로그램에서 변경 가능
- void setPriority(int priority)
- int getPriority()
main() 스레드의 우선순위 값은 초기에 5
스레드는 부모 스레드와 동일한 우선순위 값을 가지고 탄생
JVM의 스케쥴링 정책
- 철저한 우선순위 기반
- 가장 높은 우선순위의 스레드가 우선적으로 스케쥴링
- 동일한 우선순위의 스레드는 돌아가면서 스케쥴링(라운드 로빈)
main 스레드와 main() 메소드
- JVM은 응용프로그램을 실행을 시작할 때 스레드 생성 : main 스레드
- JVM은 main 스레드에게 main() 메소드 실행하도록 함
- main() 메소드가 종료해도 main 스레드가 종료하지 않을 수도 있음.
예제 13-4 : main 스레드의 정보 출력
- 스스로 종료 : return run() method
- 타 스레드에서 강제 종료 : interrupt() method 사용
InterruptedException를 통한 thread 종료 방법예제 13-5:타이머스레드 강제종료
flag를 이용한 종료
- 스레드 A가 스레드 B의 flag 를 true로 만들면, 스레드 B 가 스스로 종료하는 방식
예제 13-6 : flag를 이용한 스레드 강제 종료
멀티 스레드 프로그램 작성시 주의점
다수의 스레드가 공유 데이터에 동시에 접근하는 경우
- 공유 데이터의 값에 예상치 못한 결과 발생 가능
스레드 동기화
멀티스레드의 공유 데이터의 동시 접근 문제 해결책
- 공유 데이터를 접근하는 모든 스레드의 한 줄 세우기
- 한 스레드가 공유 데이터에 대한 작업을 끝낼 때까지 다른 스레드가 대기 하도록 함
=> 그러니깐 그냥.. 줄서서 기다리고 자기 차례에 쓴다는거임두 스레드의 프린터 동시 쓰기로 충돌하는 사례
공유 집계판에 동시 접근하는 사례
스레드 동기화
- 공유 데이터에 동시에 접근하는 다수의 스레드가 공유 데이터를 배타적으로 접근하기 위해 상호 협력(coordination)하는 것
- 동기화의 핵심
- 스레드의 공유 데이터에 대한 배타적 독점 접근 보장
자바에서 스레드 동기화를 위한 방법
- synchronized로 동기화 블록 지정
- wiat()-notify() method로 thread 실행 순서 제어
synchronized 키워드
- 한 스레드가 독점 실행해야 하는 부분(동기화 코드)을 표시하는 키워드
- 임계 영역(critical section) 표기 키워드
- 메소드 전체 혹은 코드블록
synchronized 블록에 대한 컴파일러의 처리
- 먼저 실행한 스레드가 모니터 소유
- 모니터란 해당 객체를 독점적으로 사용할 수 있는 권한
- 모니터를 소유한 스레드가 모니터를 내놓을 때까지 다른 스레드 대기
synchronized 사용 예 : 공유 집계판 사례를 코딩
SharedBoard의 add()를 스레드1이 실행하고 있는 동안, 스레드2가 호 출하면 스레드2는 대기
공유집계판 사례에서 synchronized 사용하지 않아 충돌로 인해 데이터에 오류가 발생한 경우
producer-consumer 문제와 동기화
producer-consumer 문제
- producer : 공유 메모리에 데이터를 공급하는 스레드
- consumer : 공유 메모리의 데이터를 소비하는 스레드
- 문제의본질
- producer와 consumer 가 동시에 공유 데이터를 접근하는 문제
producer-consumer 문제 사례
- 미디어 플레이어
- producer:입력스레드, consumer:재생스레드, 공유데이터:비디오버퍼
wait(), notify(), notifyAll()를 이용한 동기화
동기화 객체
- 두 개 이상의 스레드 동기화에 사용되는 객체
동기화 메소드
- synchronized 블록/메소드 내에서만 사용되어야 함
- wait()
- 다른 스레드가 notify()를 불러줄 때까지 기다린다.
- notify()
- wait()를 호출하여 대기중인 스레드를 깨우고 RUNNABLE 상태로 만든다.
- 2개 이상의 스레드가 대기중이라도 오직 한 스레드만 깨운다.
- notifyAll()
- wait()를 호출하여 대기중인 모든 스레드를 깨우고 모두 RUNNABLE 상태로 만든다.
wait(), notify(), notifyAll()은 Object의 메소드
- 모든 객체가 동기화 객체가 될 수 있다.
- Thread 객체도 동기화 객체로 사용될 수 있다.
예제 13-6 : wait(), notify()를 이용한 바 채우기
코드
실행결과