Thread가 3개 있다면 JVM은 시간을 잘게 쪼갠 후에
한 번은 Thred 1을, 한 번은 Thread 2를, 한 번은 Thred 3을 실행한다.
이것이 빠르게 일어나다 보니까 Thread가 모두 동작하는 것처럼 보이는 것이다.
Thread는 실행 가능 상태인 Runnable과 실행 상태인 Running 상태로 나뉜다.
실행되는 Thread 안에서 Thread.sleep()이나 Object가 가지고 있는 wait 메소드가 호출이 되면
Thread.sleep()은 특정 시간이 지나면 자신 스스로 블록 상태에서 빠져나와
Runnable이나 Running 상태가 된다.
Object가 가지고 있는 wait() 메소드는 다른 Thread가 nofify()나 notifyAll() 메소드를 호출하기 전에는
wait() 메소드는 호출이 되면 모니터링 락을 놓게 된다. 그래서 대기 중인 다른 메소드가 실행한다.
Thread의 run 메소드가 종료되면 Thread는 종료된다. 즉, Dead 상태가 된다.
Thread의 yeild 메소드가 호출되면 해당 Thread는 다른 Thread에게 자원을 양보하게 된다.
Thread가 가지고 있는 join 메소드를 호출하게 되면 해당 Thread가 종료될 때까지 대기하게 된다.
Thread와 상태 제어(join)
join() 메소드는 Thread가 멈출때까지 기다리게 한다.
wait을 만나게 되면 해당 Thread는 해당 객체의 모니터링 락에 대한 권한을 가지고 있다면
모니터링 락의 권한을 놓고 대기한다.
public class MyThread extends Thread{
public void run(){
for(int i = 0; i < 5; i++){
System.out.println("MyThread : "+ i);
try {
// 0.5초씩 쉬면서 출력
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class JoinExam {
public static void main(String[] args) {
MyThread thread = new MyThread();
// Thread 시작
thread.start();
System.out.println("Thread가 종료될때까지 기다립니다.");
try {
// 메인 Thread는 해당 Thread가 끝날 때까지 기다림
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread가 종료되었습니다.");
}
}
위의 코드에서 만약 thread.join() 코드가 없다면 메인 Thread(시작, 종료)부터 실행 후
해당 Thread(MyThread : i)가 실행된다.
Thread와 상태 제어(wait, notify)
wait과 notify는 동기화된 블록 안에서 사용해야 한다.
public class ThreadB extends Thread{
// 해당 Thread가 실행되면 자기 자신의 모니터링 락을 획득
// 5번 반복하면서 0.5초씩 쉬면서 total에 값을 누적
// 그 후에 notify() 메소드를 호출하여 wiat하고있는 Thread를 깨움
int total;
@Override
public void run(){
// wait와 notify는 동기화된 블록 안에서 사용해야 함
synchronized(this){
for(int i=0; i<5 ; i++){
System.out.println(i + "를 더합니다.");
total += i;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Thread를 깨울 수 있는 메소드
notify();
}
}
}
// ThreadB를 사용하며 wait하는 클래스
public class ThreadA {
public static void main(String[] args){
// 앞에서 만든 ThreadB를 만든 후 start
// 해당 Thread가 실행되면 해당 Thread는 run메소드 안에서 자신의 모니터링 락을 획득
ThreadB b = new ThreadB();
b.start();
// b에 대하여 동기화 블럭을 설정
// 만약 main Thread가 아래의 블록을 위의 Thread보다 먼저 실행되었다면
// wait를 하게 되면서 모니터링 락을 놓고 대기
synchronized(b){
try{
// b라는 Thread가 완료될 때까지 기다릴 수 있도록 b.wait()메소드를 호출
// 메인 Thread는 정지
// ThreadB가 5번 값을 더한 후 notify를 호출하게 되면 wait에서 깨어남
System.out.println("b가 완료될때까지 기다립니다.");
// 다른 Thread가 notify할 때까지 기다림
b.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
// 깨어난 후 결과를 출력
System.out.println("Total is: " + b.total);
}
}
}
실행결과
b가 완료될때까지 기다립니다.
0를 더합니다.
1를 더합니다.
2를 더합니다.
3를 더합니다.
4를 더합니다.
Total is: 10
wait에 빠져있는 상태에서는 반드시 다른 Thread가 notify 메소드를 호출해줘야 깨어난다.