Ezcho

[Java] Thread와 상태제어 본문

Java

[Java] Thread와 상태제어

Ezcho 2022. 11. 25. 14:30

1. Thread의 상태

Thread는 프로그램 실행의 가장 작은 단위이다. 우리가 이전 글에서는 MultiThread를 구현하는것을 보았는데,

그냥 저냥 프로그램을 실행시키면 그냥 main thread에서 실행하게 된다. 

 

이런 Thread도 항상 실행 될 수가 없는것이. Thread도 한개의 프로세스이기 때문에, JVM에서 동시에 처리하는것이 아닌 시간을 잘게 쪼갠 후에 여러개의 쓰레드를 순서를 두고 실행하는것을 알 수 있다.

 

우리가 CPU내 프로세스의 상태를 나타낼 때 

new, ready, running, blocked, suspended등으로 나타낼 수 있는데

JVM의 Thread역시 이렇게 현재 상태에 따라 여러 단계로 나뉠 수 있다.

 

현재 실행되는 Thread는 

 

NEW: 쓰레드 객체가 생성되었으나, 아직 start()메서드가 호출되지 않은 상태

Runnable: 실행대기 상태

Running: 실행중 상태

Blocked: 봉쇄 상태

1. WAITING: 다른 쓰레드가 통지할 때 까지 기다리는 상태

2. TIMED_WAITING: Timesleep 상태

3. BLOCKED: 락이 풀릴때까지 기다리는 상태

Dead: 쓰레드의 run메서드가 종료된 상태

 

로 나눌 수 있다.

 

2. join() 메서드

쓰레드가 멈출 때 까지 기다리게 한다. 

코드를 우선 보자

    public class joinTest extends Thread{
        public void run(){
            for(int i = 0; i < 5; i++){
                System.out.println("joinTest : "+ i);
                try {
                    Thread.sleep(500);	//0.5초씩 휴식
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public class JoinExam { 
        public static void main(String[] args) {
            joinTest thread = new joinTest();
            
            thread.start(); 
            System.out.println("Thread가 종료될때까지 기다립니다.");
            try {
                thread.join();	//join을 통해 joinTest의 running상태가 지속
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread가 종료되었습니다."); 
        }   
    }

main에서 joinTest 클래스 객체를 만들고 실행시키는데,

main역시 위에서 또 하나의 thread라고 설명했다. 즉 thread join이 없을 때, 아래와 같은 flow를 가지게 되는데,

시간(JVM에서 쪼갠) code main joinTest
... (thread.start) running  runable
1   runable running
2   running runable
3   runable running

.join()이라는 메서드를 사용한 후에는 joinTest의 running이 dead상태로 가기 전 까지 joinTest(thread객체)를 실행한다.

시간(JVM에서 쪼갠) code main joinTest
1 thread.start(); running runable
2 thread.join(); running runable
3 ... WAITING(blocked) running
4 .. WAITING(blocked) running
5 ... WAITING(blocked) running

 

3. wait()과 notify() 메서드

wait과 notify는 Synchronized된 블록 안에서 사용해야 한다.

wait 를 만나게 되면 모니터링 락의 권한을 놓고 대기하게 된다.

notify를 만나게 되면, 모니터링 락의 권한을 다시 내려놓는것을 의미한다.

 public class ThreadB extends Thread{
        int total;
        public void run(){
            synchronized(this){	//해당 동기화 블록이 모니터링 락을 획득한다.
                for(int i=0; i<5 ; i++){
                    total += i;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                notify();	//main thread를 깨운다.
            }
        }
    }
    public class ThreadA {
        public static void main(String[] args){

            ThreadB b = new ThreadB();
            b.start();
  
            synchronized(b){
                try{
                    System.out.println("b가 완료될때까지 기다립니다.");
                    b.wait();//wait을 만났다.
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("Total: " + b.total);
            }
        }
    }

표로 설명하면,

time/code main ThreadB
 ThreadB b = new ThreadB(); running NEW
b.start(); running runnable
synchronized(b){.. running runnable
b.wait(); blocked (WAITING) running
for();... //덧셈연산, threadB실행 blocked (WAITING) running
notify(); running dead
System.out.println("Total: ",b.total); running dead
  dead dead
     

wait 과 notify의 사용은 running 상태와 runnable상태로 쓰레드가 나뉘는것이 아니라, blocked 상태와 runnable, running 상태 간의 변화이다. wait()된 스레드는 반드시 notify()나 notifyAll()메소드를 호출하여 블록상태를 해제해 줄 필요가 있다는 점을 기억하자.

 

출처- 프로그래머스 자바 중급

 

4. 데몬 쓰레드

데몬(Daemon)이란 보통 리눅스와 같은 유닉스계열의 운영체제에서 백그라운드로 동작하는 프로그램을 말한다.

쓰레드에 데몬을 설정하여 데몬 쓰레드로 바꾸어 주면 된다.

public class DaemonThread implements Runnable {	//Runnable로 구현
        public void run() {
            while (true) {
                System.out.println("데몬 쓰레드가 실행중입니다.");
                try {
                    Thread.sleep(500);	//0.5초씩 쉬면서 무한으로 데몬 쓰레드를 실행시킴
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break; 		//Exception발생시 while을 탈출하게 함 
                }
            }
        }

        public static void main(String[] args) {
            Thread th = new Thread(new DaemonThread());
            th.setDaemon(true);		//th를 demon thread로 설정한다.
            th.start();				//th실행

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }   
            System.out.println("메인 쓰레드가 종료됩니다. ");    //이때 Demonthread도 함께 종료됨
        }   
    }

데몬쓰레드는 일반쓰레드(main)이 종료되면 강제적으로 종료되는 특징을 가지고 있다.

 

데몬쓰레드의 예로는 가비지컬랙션, 자동저장, 화면보호기 등이 있다.

실행 후 대기하고 있다가 어떤 조건이 만족되면 작업을 진행하고 작업이 종료되면 다시 대기하고 있는다.

 

'Java' 카테고리의 다른 글

[Java] Thread  (0) 2022.11.25
[java] java IO - Byte단위 입출력  (0) 2022.11.16
[java] 어노테이션  (0) 2022.11.09
[java] Date, Calendar클래스, Time 패키지  (0) 2022.11.09
[java] java.util패키지  (0) 2022.11.02
Comments