서버 개발/Thread

Java Thread - (2) 제어

Johnny Yoon 2019. 7. 19. 19:36
728x90
반응형

 

 

 

 

Thread 제어

Thread 일종의 생명주기 (LifeCycle)을 가집니다.

보통은 start()메소드를 호출해 쓰레드가 작업을 시작하게 합니다.

이번 포스팅에서는 몇가지 Thread를 제어하는 메소드들을 알아보고자 합니다.

  • Thread.sleep() - static메소드로 현재 이 메소드를 호출하는 Thread가 일정 시간동안 멈춰있게 합니다.
  • wait() / join() - 2개 혹은 그 이상의 Thread들을 기다리거나 협업할 수 있게 합니다.
  • interrupt() - sleep중이거나 wait중인 Thread들을 재가동 시킵니다.

위의 메소드들에 대한 예제를 구현해보겠습니다.

 

sleep

sleep중인 Thread는 아무것도 하지 않고 기다리는 상태 (IDLE상태)입니다.

이 작업은 일정 시간동안 아무 입력도 받지 않을 수 있고, 작업을 수행하지 않습니다.

다른 Thread들과 경쟁하지도 않고, 거의 CPU를 쓰지 않는 상태입니다.

아래는 CounterThread에 sleep을 적용한 예제입니다.

public class CounterRunnableSleep implements Runnable {
    private int counter = 0;
    private boolean running = true;

    Thread thread;

    public CounterRunnableSleep(){
        thread = new Thread(this);
        thread.run();
    }

    @Override
    public void run() {
        while (running){
            counter++;
            System.out.println(counter);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (counter >= 10) running = false;
        }
    }

    public static void main(String[] args) {
        Runnable thread = new CounterRunnableSleep();
    }
}

 

결과를 보시면 아래와 같이 1초에 한번씩 총 10번 숫자를 출력합니다.

> Task :CounterRunnableSleep.main()
1
2
3
4
5
6
7
8
9
10

 

join

Join은 조금 하드한 방법의 동기화 기법입니다.

소프트하게 동기화를 하는 방법은 synchronized라는 방법이 있는데, 나중에 살펴보도록 하겠습니다.

join메소드는 한 Thread가 다른 Thread가 한 시점에서 만날 수 있도록 해주는 메소드 입니다.

join메소드는 일정시간 기다리다가 포기하게 하도록 시간을 지정해 줄 수도 있고,

무작정 기다리게도 할 수 있습니다.

다음은 join을 사용한 예제입니다.

public class CounterThreadJoin extends Thread {
    private int counter = 0;
    private boolean running = true;

    @Override
    public void run() {
        while (running){
            counter++;
            System.out.println(counter);
            if (counter >= 10) running = false;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        String mainThreadName = Thread.currentThread().getName();
        CounterThreadJoin thread = new CounterThreadJoin();
        thread.start();

        System.out.println(String.format("%s, started", mainThreadName));
        thread.join();
        System.out.println(String.format("%s, terminated", mainThreadName));

    }
}

위의 코드의 main메소드를 보면, main Thread가 CounterThread를 join을 통해 기다리게 됩니다.

main Thread는 원래 모든 Thread가 종료될때까지 기다리지는 않습니다.

하지만 위 예제에서는 join을 호출해주었기 때문에 main Thread는 바로 종료하지 않고 기다렸다가 종료하게 됩니다.

 

위 코드의 실행 결과는 다음과 같습니다.

> Task :CounterThreadJoin.main()
1
main, started
2
3
4
5
6
7
8
9
10
main, terminated

 

interrupt

interrupt메소드는 Thread가 sleep중이거나 wait중일 때 이 상태를 캔슬 시키고 재구동하게하는 방법입니다.

이번에는 두개의 Thread를 따로 구현해서 실험을 해보도록 하겠습니다.

먼저 CounterThreadSleep을 구현해줍니다. 이 Thread는 10초에 한번씩 숫자를 print하게 되어있습니다.

public class CounterThreadSleep  extends Thread {
    private int counter = 0;
    private boolean running = true;

    @Override
    public void run() {
        while (running){
            counter++;
            System.out.println(counter);
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                System.out.println("Thread has been interrupted!");
            }
            if (counter >= 10) running = false;
        }
    }
}

 

그리고 InterrupterThread를 구현해주겠습니다.

이 Thread는 3초간 sleep하다가 생성자에서 받아준 Thread를 interrupt시킵니다.

public class InterrupterThread extends Thread {
    CounterThreadSleep counterThread;

    public InterrupterThread(CounterThreadSleep counterThread){
        this.counterThread = counterThread;
    }

    @Override
    public void run() {
        System.out.println("Interrupter started");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        counterThread.interrupt();
        System.out.println("Interrupter ended");
    }

    public static void main(String[] args) throws InterruptedException {
        CounterThreadSleep counterThread = new CounterThreadSleep();
        InterrupterThread interrupterThread = new InterrupterThread(counterThread);
        counterThread.start();
        interrupterThread.start();
    }
}

하단의 main함수에서는 두개의 Thread를 모두 초기화 시키고 start를 해주고 있습니다.

 

이 코드의 실행 결과는 다음과 같습니다.

> Task :InterrupterThread.main()
1
Interrupter started
Interrupter ended
Thread has been interrupted!
2
3
4
5
6
7
8
9
10

실행을 해보시면, 원래대로라면 실행을 하고 10초간 기다려야 하지만,

interrupt가 되기 때문에 Interrupter가 ended되고, CounterThread가 Interrupt되면서, 바로 2가 나오는 것을 보실 수 있습니다.

 

참고자료: Learning Java, 4th Edition, Orielly 

 

728x90
반응형

'서버 개발 > Thread' 카테고리의 다른 글

Java Thread - (3) 동기화  (0) 2019.08.05
Java Thread - (1) 기본 개념  (0) 2019.07.17