Thread2
1. 쓰레드
(1) 쓰레드 동작과정
Thread 크래스 상속 또는 Runnable 인터페이스를 통해 run()메소드 구현
쓰레드 객체 생성
start() 메소드 호출
쓰레드 실행
쓰레드 종료
(2) 쓰레드 상태
쓰레드는 생성된 후부터 종료될때까지 여러 상태를 가질 수 있다
1) 상태 의미
a. NEW : 쓰레드가 생성되고 아직 start()메소드가 호출되지 않은 상태
b. RUNNABLE : 실행 중 또는 실행가능한 상태
c. BLOCKED : 동기화블록에 의해서 일시정지된 상태(lock이 풀릴 때 까지 기다리는 상태)
d. WAITING : 쓰레드의 작업이 종료되지 않았지만 실행가능하지 않은(unrunnable) 일시정지 상태,
e. TIMED_WAITING : 일시정지 시간이 지정된 상태
f. TERMINATED : 쓰레드의 작업이 종료된 상태
2) 객체생성 -> start() 호출 -> 실행 -> 실행대기 -> 실행 -> 실행완료
NEW -> RUNNABLE -> RUNNING -> WAITING / BLOCKED / TIMED_WAITING -> RUNNING -> TERMINATED
3) 쓰레드를 처리할 로직 run() 메소드에서 구현하고 Thread 클래스의 start() 메소드를 이용해 실행
-> 실행 대기 상태로 들어가(JVM의 스케쥴링에 의해 실행할 수 있는 상태)
자바 프로그램은 JVM에 의해 실행되는 쓰레드가 결정되면 이것을 스케쥴링이라고 한다
2. 동기화(Synchronization)
A쓰레드와 B쓰레드가 작업을 진행할 때 A가 사용중인 자원을 B가 사용하여 변경한다면 A의 작업의도와
다른 결과가 나타날 수 있다.
이런 문제를 방지하기 위해 하나의 자원을 여러 쓰레드가 동시에 접근하지 못하게 막는 것을 동기화 라고 한다
(1) 동기화 영역 만들기
Synchronized(객체명){...} : 동기화 블록
일부 소스코드만 동기화를 걸어준다
쓰레드는 지정된 객체의 lock을 얻어내며 해당 객체의 lock을 가진 쓰레드만 동기화 블록에 접근이 가능하다
synchronized 리턴타입 메소드명(){...} : 동기화 메소드
해당 메소드 전체에 동기화를 걸어준다
(2) lock
쓰레드가 공유되는 자원을 사용할 때 생기는 문제를 동기화로 해결한다
이 때 하나의 자원에 하나의 쓰레드만 접근하기위해 사용하는 개념이 lock이다
자바의 모든 객체는 하나의 lock을 가지고 있다
동기화된 영역을 쓰레드가 사용하기 위해서는 lock을 획득해야만 하며,
동기화 영역을 벗어나면 lock을 반납하고 다른 쓰레드가 lock을 가져와 자원을 사용한다
3. 쓰레드 제어 메소드
(1) sleep(long millis) : 매개변수로 전달한 시간동안 쓰레드를 멈춘다
(2) join() join(millis) : 현재쓰레드의 작업을 멈추고 join()을 사용한 쓰레드를 기다린다
(3) wait() 동기화된 영역에서만 사용가능
쓰레드의 lock을 회수하여 다른 쓰레드에게 제어권을 넘겨주고 대기한다
(대기중에는 lock을 얻을 수 없다)
(4) notify() 동기화된 영역에서만 사용가능
대기중인 쓰레드 중 하나를 깨운다
(실행가능한 상태로만 바뀌고 lock을 바로 넘겨주는게 아니다)
(5) interrupt()
sleep(), wait(), join()을 사용하여 쓰레드가 멈췄을때 interrupt()를 사용하면 예외를 발생시킬 수 있다
InterruptException은 쓰레드가 멈출 때 사용하는 일종의 신호라 생각하면 된다
interrupt() 메소드는 쓰레드 종료에 사용된다
4. Thread 종료방법
(1) 쓰레드 객체의 interrupt()를 사용하여 InterruptException을 발생시켜 try~catch문으로 이동시킨다
여기서 InterruptException은 쓰레드를 대기사앹로 만드는 sleep(),wait(),join()등의 메소드를 사용한 곳에서 발생된다
위의 메소드들에 예외처리하고 interrupt()를 통해 예외를 발생시키면 쓰레드의 흐름이 해당 메소드의
catch문으로 이동된다
예외처리를 했다고 해서 강제 종료가 되는 것이 아니기 때문에 catch문에서 쓰레드가 종료될 수 잇는 코드를 작성하여 처리해야한다
(2) System.exit(0) 을 사용하면 전체 쓰레드가 종료된다(프로그램 종료)
(3) 쓰레드 객체를 대기사앹로 만드는 메소드를 사용하지 않았을 경우 Thread.interrupted()를 사용하면
interrupt()의 사용여부를 boolean 타입으로 반환하다
쓰레드의 흐름을 제어할 수 있다
단, interrupted()를 한 번 사용하거나 예외처리로 catch문으로 이동하면 interrupted()다시 false를 반환한다