스레드의 상태

 

스레드의 제어

스레드를 만들고 시작하는 것보다 스레드를 제어 하는 것이 더 중요 하다.


스레드 제어의 기본

스레드를 제대로 제어하려면 스레드의 상태부터 알아야 한다.


스레드의 상태

시작 상태(Start 상태)

동작할 수 있는 상태(Runnable 상태)

동작 상태(Run 상태)

대기 상태(NotRunnable 상태)

종료 상태(Dead 상태)


제일 먼저 스레드를 만든 후 start()를 호출햇을 때 Start 상태가 된다. 그리고 바로 Runnable 상태로 진입하게 된다.

Runnable 상태에서 CPU의 제어권을 할당 받는 순간 Run 상태가 되었다가 일정 시간 동안 작압을 한 후 Runnable 상태도 되돌아와서 자신의 순서가 되기를 기다린다. 결국 Runnable 상태에 있는 스레드끼리 작업을 번갈아 가면서 처리 하는 방식이며, 몇번의 Run 상태를 거친 후 모든 작업을 완료 하면 Dead 상태가 된다.


그런데 NotRunnable 상태는 약간 다르다, NotRunnable 상태는 Runnable 상태를 벗어나 잠깐 쉬고 있는 상태라 할 수 있다.

즉, Run 상태에 진입할 수는 없지만, Dead 상태는 아닌 쉽게 대기 상태라고 한다.


NotRunnable 상태의 경우에는 프로그래머가 직접 제어 해줘야 하다. 

NotRunnable 상태를 만드는 방법

sleep() 은 일정 시간동안만 NotRunnable 상태로 만든다.

wait()와 notify()는 수동으로 NotRunnable 상태로 되돌아가고 나오는 것을 제어할 수 있다.

* 사실 스레드에서 제일 까다로운 것이 wait()와 notify()이다. 이부분은 추후에 다시 정리 하도록 하자.


스레드의 우선권


스레드 우선권(Priority)을 어떻게 주느냐에 따라서 스레드의 작업 순서가 달라진다. 달라 진다는 것은 Runnable 상테에서 얼마나 자주 Run 상태가 될 수 있느냐를 말한다. 우선권이 높다면 Run 상태가 될 확율이 높다.

스레드에 할당할 수 있는 스레드의 우선권 상수는 다음과 같다.

public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY =10;


public class PriorityThreadMain {
    public static void main(String[] args) {
        System.out.println("Main 메서드 시작");
        for (int i = 1; i <= 10; i++) {
            PriorityThread s = new PriorityThread();
            s.setPriority(i);
            s.start();
        }
        System.out.println("Main 메서드 종료");
    }
}

class PriorityThread extends Thread {
    @Override
    public void run() {
        int i = 0;
        System.out.print(this.getName());
        System.out.println("[우선권:" + this.getPriority() + "] 시작\t");
        while (i < 1000) {
            i++;
            try {
                this.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print(this.getName());
            System.out.println("[우선권:" + this.getPriority() + "] 종료\t");
        }
    }
}

일반적으로 스레드는 지속적인 작업을 목적으로 하기 때문에 일정 시가동안 작업을 멈추게 하는 것이 반드시 필요하다. 하나의 스레드가 CPU를 독점하는 것을 막기 위해서 sleep()는 간다하면서도 효과 적인 방법이다.

만약 sleep() 없이 장시간의 스레드 작업을 실행 하다면, Windows의 경우 "응답없음" 이라는 메시지를 만나게 될 것이다.

보통의 경우에는 하느의 스레드를 제어하는 것이 아니라 여러 개의 스레드를 동시에 제어 하게 된다. 이 때 sleep()을 이용해서 작업의 로드 밸런싱을 하게 되다.



쓰레드 종료


스레드의 종료

run() 메소드의 종료는 스레드의 종료를 의미한다.

일반적으로 지속적인 작업을 하기 위해 run() 내에 while문을 포함하고 있으며, 이 while문이 끝나면 스레드가 종료되는 경우가 많다.

*Thread에는 stop() 라는 메소드가 제공되지만, 이는 Deprecated 되었다. 이 의미는 stop() 메소드는 안전하지 못하며 권장하지 않는다는 의미 이다.

public class TerminateThreadMain {
    public static void main(String[] args) throws IOException {
        System.out.println("작업시작");
        TerminateThread a = new TerminateThread();
        TerminateThread b = new TerminateThread();
        TerminateThread c = new TerminateThread();
        a.start();
        b.start();
        c.start();
        int i;
        System.out.println("종료할 스레드를 입력하시오! A, B, C, M?\n");
        while (true) {
            i = System.in.read();
            if (i == 'A') {
                a.setFlag(true);
            } else if (i == 'B') {
                b.setFlag(true);
            } else if (i == 'C') {
                c.setFlag(true);
            } else if (i == 'M') {
                a.setFlag(true);
                b.setFlag(true);
                c.setFlag(true);
                System.out.println("Main 종료");
                break;
            }
        }

    }
}

class TerminateThread extends Thread {
    private boolean flag = false;

    @Override
    public void run() {
        System.out.println(this.getName() + "시작");
        while (!flag) {
            try {
                this.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(this.getName() + "종료");
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}


public class ControlThreadMain {
    public static void main(String[] args) throws IOException {
        System.out.println("작업시작");
        ControlThread a = new ControlThread();
        ControlThread b = new ControlThread();
        ControlThread c = new ControlThread();
        a.start();
        b.start();
        c.start();
        int i;
        System.out.println("종료할 스레드를 입력하시오! A, B, C, M?\n");
        while (true) {
            i = System.in.read();
            if (i == 'A') {
                a.setFlag(true);
            } else if (i == 'B') {
                b.setFlag(true);
            } else if (i == 'C') {
                c.setFlag(true);
            } else if (i == 'M') {
                ControlThread.all_exit = true;
                System.out.println("Main 종료");
                break;
            }
        }

    }
}

class ControlThread extends Thread {
    public static boolean all_exit = false;
    private boolean flag = false;

    @Override
    public void run() {
        System.out.println(this.getName() + "시작");
        while (!flag && !all_exit) {
            try {
                this.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(this.getName() + "종료");
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

'JAVA > in 기초' 카테고리의 다른 글

[JAVA8]Stream 맛보기  (0) 2014.12.02
스레드 기본(3)  (0) 2014.03.05
스레드 기본(2)  (0) 2014.03.05
static 변수는 하나의 프로세스에서 하나의 값만 가진다.  (0) 2014.03.05
스레드 기본(1)  (0) 2014.03.05
가변 인수(Varargs)  (0) 2014.02.23
Posted by lahuman

댓글을 달아 주세요