JAVA 12. 쓰레드 상태, 제어

김창민·2024년 7월 29일

BE

목록 보기
14/50


JAVA 11.에서 이어집니다.

쓰레드 상태

쓰레드는 기본적으로 생성 -> 대기 <-(일시정지)-> 실행 -> 종료의 5상태를 갖게 되며, 각 상태로 제어할 수 있는 메소드가 제공된다.

sleep()

지정된 시간동안 일시정지

Runnable task = ()->{
	try{
    	for(int i=0;i<100;i++){
        	System.out.println(Thread.currentThread().getName());
            Thread.sleep(1000);
        }
    }catch (InterruptedException e){
    	e.printStackTrace();
        }
    };
ThreadGroup G1 = new ThreadGroup("G1");
Thread task1 = new Thread(G1, task, "쓰레드 1");
Thread task2 = new Thread(G1, task, "쓰레드 2");
task1.start();
task2.start();

try문에 Thread.sleep(1000);를 통해 1000ms, 즉 1초동안 정지시키는 코드다. sleep은 자기 자신에 대해서만 동작하기 때문에 Thread 내부 로직에서 사용해야한다.

sleep은 후술할 interrupt를 만나면 다시 실행되므로 InterruptedException 예외처리가 필요하다.

interrupt()

쓰레드를 실행 대기 상태로 전환.

쓰레드를 실행 대기 상태로 전환한다.

public static void main(String[] args) {
        Runnable task = ()->{
            try{
                for(int i=0;i<100;i++){
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }catch (InterruptedException e){
                System.out.println(Thread.currentThread().getName()+"인터럽트 발생");
            }
            System.out.println(Thread.currentThread().getName()+"종료");
        };

        ThreadGroup G1 = new ThreadGroup("G1");
        Thread task1 = new Thread(G1, task, "쓰레드 1");
        Thread task2 = new Thread(G1, task, "쓰레드 2");

        task1.start();
        task2.start();

        task1.interrupt();
    }
 public static void main(String[] args) {
        Runnable task = ()->{
            while (!Thread.currentThread().isInterrupted()) {
                try {
                     System.out.println(Thread.currentThread().getName());
                     Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()+" 인터럽트 발생");
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName()+"");
        };

        ThreadGroup G1 = new ThreadGroup("G1");
        Thread task1 = new Thread(G1, task, "쓰레드 1");
        Thread task2 = new Thread(G1, task, "쓰레드 2");

        task1.start();
        task2.start();

        task1.interrupt();
    }

두 코드 모두 인터럽트를 유도하고, 처리하는 코드다. 위의 경우 그냥 돌리는거고 아래의 경우 while (!Thread.currentThread().isInterrupted())를 통해서 계속 인터럽트의 상태 flag를 확인하는 건데, 아래 코드가 오류를 방지하고 하기 때문에 더 안전한 코드다.

join()

다른 쓰레드의 작업을 기다린다.

쓰레드명.join(ms)로 사용하는 이 메서드는 작성한 쓰레드에서 동작하며, 쓰레드명으로 지정한 쓰레드가 작업하는걸 기다린다. 시간 미지정시 종료까지 기다린다.

join도 역시 예외처리는 필수다.

말로만 보면 뭔말인가 싶은데 사용하면 다음과 같다.
사용전사용후
위가 사용전, 아래가 사용훈데, main 쓰레드에 sout(하이)를 적고 join문을 적용하고 안적용하고의 차이다. 위는 하이가 언제 출력되던 출력은 됐는데, 아래는 출력이 아예 안된다.

 task1.start();
        task2.start();

        try{
            task1.join();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("하이");

yield()

내 리소스를 다음 쓰레드에게 전부 양보하기

public class Main {
    public static void main(String[] args) {
        Runnable task = ()->{
            try{
                for(int i=0;i<100;i++){
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }catch (InterruptedException e){
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName()+"종료");
        };

        ThreadGroup G1 = new ThreadGroup("G1");
        Thread task1 = new Thread(G1, task, "쓰레드 1");
        Thread task2 = new Thread(G1, task, "쓰레드 2");

        task1.start();
        task2.start();

        try{
            Thread.sleep(4000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        task1.interrupt();
    }
}

Main쓰레드에서 task1의 인터럽트를 발생시키고, task1은 동작하다가 인터럽트되어 catch문으로 빠지게 되고, 해당 문에서 Thread.yield()를 통해서 다음 쓰레드인 task2에게 모든 리소스를 넘긴다.

단, 다음 쓰레드라는건 스케줄러가 판단해서 코드 작성자는 어떤 쓰레드인지는 모른다.

profile
일일 회고 : https://rlackdals981010.github.io/

0개의 댓글