프로그래밍 공부/JAVA

JAVA중급강의 정리 어노테이션, 쓰레드

Wonuk 2021. 8. 27. 01:50
반응형

본 포스팅은 프로그래머스 자바 중급 강의에 기반하여 작성되었습니다.

자바 강의의 모든 내용이 적힌것이 아닌 복습시 놓쳤던 부분을 하나하나 정리한 내용입니다.

 

순서 어노테이션, Thread란?, Thread만들기, Thread와 공유객체, 동기화 메소드와 동기화 블록, Thread 상태제어

join, wait, notify

 


 

컴파일할때나 런타임 때 어노테이션에 적은 설정값대로 실행되게 하기위해서 사용한다.

 

어노테이션

 

실무에서도 많이 사용된다 100퍼센트 확률

 

어노테이션은 Java5에 추가된 기능

  • 어노테이션클래스나 메소드위에 붙습니다. @(at)기호로 이름이 시작합니다. ex) @Override
  • 소스코드에 메타코드(추가정보)를 주는것
  • 어노테이션을 클래스나 메타코드에 붙인 후, 클래스가 컴파일되거나 실행될 때 어노테이션의 유무나 어노테이션에 설정된 값을 통하여 클래스가 좀 더 다르게 실행되게 할 수 있습니다.이런 이유로 어노테이션을     일정의 설정파일처럼 설명하는 경우도 있습니다.
  • 어노테이션은 자바가 기본으로 제공해주는 것도 있고, 사용자가 직접 만들 수도 있습니다.
    • 사용자가 직접 작성하는 어노테이션을 Custom 어노테이션이라고 말합니다.
  • 커스텀 어노테이션을 이용하는 방법
    1. 어노테이션을 정의한다.
    2. 어노테이션을 클래스에서 사용한다. (타겟에 적용)
    3. 어노테이션을 이용하여 실행.
  • 패키지 익스플로러에서 [new - Annotation]을 이용하여 Count100이라는 어노테이션 생성
    • Count100어노테이션을 JVM실행시에 감지할 수 있도록 하려면 @Retention(RetentionPolicy.RUNTIME)를 붙여줘야 합니다.

 

    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Count100 {

    }

 

 

  • "hello"를 출력하는 hello()메소드를 가지는 MyHello라는 클래스를 작성
    • hello메소드 위에 @Count100 어노테이션을 붙힙니다.
    public class MyHello {
        @Count100
        public void hello(){
            System.out.println("hello");
        }
    }

 

 

  • MyHello클래스를 이용하는 MyHelloExam클래스를 작성
    • MyHello의 hello메소드가 @Count100어노테이션이 설정되어 있을 경우, hello()메소드를 100번 호출하도록 합니다.
    • 어노테이션이 적용되어있지 않다면 hello()메소드는 한번만 호출되도록 한다
    import java.lang.reflect.Method;

    public class MyHelloExam {
        public static void main(String[] args) {
            MyHello hello = new MyHello();
			
            try{
                Method method = hello.getClass().getDeclaredMethod("hello");
                // getClass() 메소드는 해당 인스턴스를 만들 때 사용할 클래스의 정보를 리턴
                // getDeclaredMethod() hello라는 이름의 method에 대한 정보를 구해라
            if(method.isAnnotationPresent(Count100.class)){
            // 어노테이션이 적용 되어있으면 true를 리턴
                    for(int i = 0; i < 100; i++){
                        hello.hello();
                    }
                }else{
                    hello.hello();
                }
            }catch(Exception ex){
                ex.printStackTrace();
            }       
        }
    }

 

 

 

어노테이션을 조금 더 자세히 알아보고 싶다면

해당 링크를 참고하자.

 

https://elfinlas.github.io/2017/12/14/java-annotation/

 

Java에서 어노테이션(Annotation)이란?

Java에서 어노테이션(Annotation) 이란?자바 개발을 하다 보면 클래스 또는 메서드 또는 변수 앞에 @Override 같은 @ 표시를 많이 봤을 것입니다.이 어노테이션은 JEE5(Java Platform, Enterprise Edition 5)부터 새

elfinlas.github.io

 

 

 


 

 

운영 체제(Operating System) 란?
컴퓨터의 하드웨어를 사용하게 해주는 프로그램
요즘 사용하는 대부분의 OS들은 동시에 여러가지 작업을 수행할 수 있다.
예) 음악을 들으면서, 다운로드를 하면서, 워드작업을 할 수 있다.

프로세스(Process) 란?
현재 실행되고 있는 프로그램
각 프로그램마다 메모리를 사용하고있다
하나의 프로세스 안에서도 여러개의 흐름이 동작할 수 있다. 이것을 Thread라고 한다.
예) 워드프로세서 작성 중 오타 발생시 빨간줄 출력

JVM도 프로그램중에 하나이다.

운영체제 입장으로 보면 JAVA도 하나의 프로세스로 실행하는것이다.

 

Thread

Thrad란? 여러가지 작업을 동시에 수행할 수 있게하는것

  • 동시에 여러가지 작업을 수행할 수 있습니다.
  • 프로세스란 현재 실행되고 있는 프로그램을 말합니다.
  • 자바 프로그램은 JVM에 위해 실행된다. 이 JVM도 프로그램중에 하나이다.
  • 운영체제 입장으로 보면 자바도 하나의 프로세스로 실행을 하는 것입니다.
  • 워드프로세서가 하나의 프로세스라면, 하나의 프로세스 안에서도 여러개의 흐름이 동작할 수 있다. 이것은 Thread라고 말을 합니다.
  • 자바 프로그램이 여러개의 작업을 동시에 하게 만들고 싶다면 Thread를 공부해야 합니다.

 

 

쓰레드 만들기(extend Thread)

Thread를 만드는 방법은 크게 Thread 클래스를 상속받는 방법과 Runnable인터페이스를 구현하는 방법이 있다.

 

 

  • Thread를 상속 받아서 쓰레드를 생성하는 방법
    • java.lang.Thread클래스를 상속받는다. 그리고 Thread가 가지고 있는 run()메소드를 오버라이딩한다.
    • 10번 반복하면서 str을 찍습니다.

run()메소드를 다른 흐름의 main()메소드 정도로 인식한다면 이해하기 편하다.

    public class MyThread1 extends Thread {
        String str;
        public MyThread1(String str){
            this.str = str;
        }

        public void run(){
            for(int i = 0; i < 10; i ++){
                System.out.print(str);
                // 생성자에서 받아들인 str을 10번 출력
                try {
                // 컴퓨터가 너무 빠르기 때문에 수행결과를 잘 확인 할 수 없어서
                // Thread.sleep() 메서드를 이용해서 조금씩 
                // 쉬었다가 출력할 수 있게한다. 
                    Thread.sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } 
        } 
    }

Math.random() 메소드는 0.0~1.0 사이의 값을 랜덤으로 반환한다

Thread.sleep(long millis) 메소드는 long타입의 millisecond동안 Thread가 멈추게 해준다.

 

 

  • Thread 클래스를 상속받은 MyThread1을 사용하는 클래스 ThreadExam1
    • Thread를 상속 받았으므로 MyThread1은 Thread 이다.
    • 쓰레드를 생성하고, Thread 클래스가 가지고 있는 start() 메소드를 호출 한다.
    public class ThreadExam1 {
        public static void main(String[] args) {
            // MyThread인스턴스를 2개 만듭니다. 
            MyThread1 t1 = new MyThread1("*");
            MyThread1 t2 = new MyThread1("-");

            t1.start();
            t2.start();
            System.out.print("main end !!!");  // Thread가 다 실행되면 출력할 내용
        }   
    }

Thread 동작시 run()이 아닌 start()를 호출해야한다.

start()메소드는 Thread가 실행할 준비를 해주게 하는 메소드이다. 준비가 다 되면 run()메소드를 호출한다.

즉, start()메소드를 호출하지 않으면 Thread는 동작하지 않는다.

 

main Thread가 종료되었다 하더라도 모든 Thread가 다 실행되어 종료가 되어야지만 프로그램이 종료된다.

 

실행결과

main end !!!

*

-

*

*

-

*

-

-

*

*

*

이런식으로 나오게된다.

 

 

 

 

쓰레드 만들기(implements Runnable)

 

자바에서 Thread를 만드는 방법은 크게

1. Thread 클래스를 상속받는 방법과

2. Runnable인터페이스를 구현하는 방법이 있다.

 

자바에서 Runnable 인터페이스를 통하여 Thread를 만들 수 있게 해주는 이유는
JAVA는 단일상속만 지원하기 때문에 이미 다른 클래스를 상속받고 있을 경우에
Thread를 사용할 수 있게 하기위함

 

 

 

  • Runnable인터페이스를 구현해서 쓰레드를 만드는 방법
    • Runnable 인터페이스를 implements하는 MyThread2 클래스 생성
    • Runable 인터페이스가 가지고 있는 run()메소드를 구현해야한다.
    public class MyThread2 implements Runnable {
        String str;
        public MyThread2(String str){
            this.str = str;
        }

        public void run(){ // 위의 지난 예제와 같은것으로 구현
            for(int i = 0; i < 10; i ++){
                System.out.print(str);
                try {
                    Thread.sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } 
        } 
    }

 

 

  • Runable 인터페이스를 구현한 MyThread2 사용하는 ThreadExam2
    • MyThread2는 Thread를 상속받지 않았기 때문에 Thread가 아니다.
    • MyThread2는 start()메소드가 없고 run()메소드 뿐이다. 즉, start()를 호출할 수 없다.
    • 사용하려면 Thread를 생성하고, 해당 생성자에 MyThread2를 넣어서 Thread를 생성한다.
    • Thread 클래스가 가진 start()메소드를 호출한다.

 

Thread의 생성자중에 하나인 Thread(Runnable target)

Runnable을 매개변수로 받아 Thread를 생성가능하다.

    public class ThreadExam2 {  
        public static void main(String[] args) {
            MyThread2 r1 = new MyThread2("*");
            MyThread2 r2 = new MyThread2("-");

            Thread t1 = new Thread(r1);
            Thread t2 = new Thread(r2);

            t1.start();
            t2.start();
            
            System.out.println("main end!!!");
        }   
    }

위의 Thread를 상속받은 클래스를 실행시킨 실행결과와 똑같은 결과가 나온다.

 

 

 

 

쓰레드와 공유객체

공유객체

 

하나의 객체를 여러개의 Thread가 사용한다는 것을 의미

 

MusicBox라는 클래스가 있다고 가정하겠습니다. 해당 클래스는 3개의 메소드를 가지고 있습니다.
각각의 메소드는 1초 이하의 시간동안 10번 반복하면서, 어떤 음악을 출력합니다.
이러한 MusicBox를 사용하는 MusicPlayer를 3명 만들어 보도록 하겠습니다.
MusicPlayer3명은 하나의 MusicBox를 사용할 것입니다.
이때 어떤 일이 발생하는지 살펴보도록 하겠습니다.

 

 

 

 

  • 공유객체 MusicBox
    public class MusicBox { 
        //신나는 음악!!! 이란 메시지가 1초이하로 쉬면서 10번 반복출력
        public void playMusicA(){
            for(int i = 0; i < 10; i ++){
                System.out.println("신나는 음악!!!");
                try {
                    Thread.sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } // for        
        } //playMusicA

        //슬픈 음악!!!이란 메시지가 1초이하로 쉬면서 10번 반복출력
        public void playMusicB(){
            for(int i = 0; i < 10; i ++){
                System.out.println("슬픈 음악!!!");
                try {
                    Thread.sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } // for        
        } //playMusicB
        //카페 음악!!! 이란 메시지가 1초이하로 쉬면서 10번 반복출력
        public void playMusicC(){
            for(int i = 0; i < 10; i ++){
                System.out.println("카페 음악!!!");
                try {
                    Thread.sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } // for        
        } //playMusicC  
    }

 

 

  • MusicBox를 가지는 Thread객체 MusicPlayer
    public class MusicPlayer extends Thread{
        int type;
        MusicBox musicBox;  
        // 생성자로 부터 musicBox와 정수를 하나 받아들여서 필드를 초기화
        public MusicPlayer(int type, MusicBox musicBox){
            this.type = type;
            this.musicBox = musicBox;
        }       
        // type이 무엇이냐에 따라서 musicBox가 가지고 있는 메소드가 다르게 호출
        public void run(){
            switch(type){
                case 1 : musicBox.playMusicA(); break;
                case 2 : musicBox.playMusicB(); break;
                case 3 : musicBox.playMusicC(); break;
            }
        }       
    }

 

 

  • MusicBox와 MusicPlayer를 이용하는 MusicBoxExam1 클래스
    public class MusicBoxExam1 {

        public static void main(String[] args) {
            // MusicBox 인스턴스
            MusicBox box = new MusicBox();

            MusicPlayer kim = new MusicPlayer(1, box);
            MusicPlayer lee = new MusicPlayer(2, box);
            MusicPlayer kang = new MusicPlayer(3, box);

            // MusicPlayer쓰레드를 실행합니다. 
            kim.start();
            lee.start();
            kang.start();           
        }   
    }

 

실행결과

슬픈음악!!!

슬픈음악!!!

카페음악!!!

슬픈음악!!!

신나는음악!!!

...

 

 

 

 

동기화 메소드와 동기화 블록

  • 공유객체가 가진 메소드를 동시에 호출 되지 않도록 하는 방법
    • 메소드 앞에 synchronized 를 붙힌다.
    • 여러개의 Thread들이 공유객체의 메소드를 사용할 때 메소드에 synchronized가 붙어 있을 경우 먼저 호출한 메소드가 객체의 사용권(Monitoring Lock)을 얻는다.
    public synchronized void playMusicA(){
        for(int i = 0; i < 10; i ++){
            System.out.println("신나는 음악!!!");
            try {
                Thread.sleep((int)(Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } // for        
    } //playMusicA
    
     //슬픈 음악!!!이란 메시지가 1초이하로 쉬면서 10번 반복출력
        public synchronized void playMusicB(){
            for(int i = 0; i < 10; i ++){
                System.out.println("슬픈 음악!!!");
                try {
                    Thread.sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } // for        
        } //playMusicB
        //카페 음악!!! 이란 메시지가 1초이하로 쉬면서 10번 반복출력
        public void playMusicC(){
            for(int i = 0; i < 10; i ++){
                System.out.println("카페 음악!!!");
                try {
                    Thread.sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();

실행결과

카페 음악!!!은

synchronized가 붙은 메소드들이 실행됨과 상관없이

동시에 실행된다. 따라서

신나는 음악!!

카페 음악!!!

신나는 음악!!

신나는 음악!!

카페 음악!!!

신나는 음악!!

신나는 음악!! 10번

슬픈 음악!!

카페 음악!!!

슬픈 음악!!

슬픈 음악!!

카페 음악!!!

슬픈 음악!! 10번

카페 음악!!!

 

이런 형식으로 출력이된다.

 

  • 메소드 앞에 synchronized 를 붙혀서 실행해 보면, 메소드 하나가 모두 실행된 후에 다음 메소드가 실행된다.
  • 0.000001초라도 메소드가 먼저 실행이되면 해당객체의 사용권을 얻게된다. 여기서 사용권을 모니터링 락이라 한다.
  • 해당 모니터링 락메소드 실행이 종료되거나, wait()와 같은 메소드를 만나기 전까지 유지된다.
  • 다른 쓰레드들은 모니터링 락을 놓을때까지 대기한다.
  • synchronized를 붙히지 않은 메소드는 다른 쓰레드들이 synchronized메소드를 실행하면서 모니터링 락을 획득했다 하더라도, 그것과 상관없이 실행된다.
  • synchronized를 메소드에 붙혀서 사용 할 경우, 메소드의 코드가 길어지면, 마지막에 대기하는 쓰레드가 너무 오래 기다리는것을 막기위해서 메소드에 synchronized를 붙이지 않고, 문제가 있을것 같은 부분만 synchronized블록을 사용한다.
    public void playMusicB(){
        for(int i = 0; i < 10; i ++){
            synchronized(this){
                System.out.println("슬픈 음악!!!");
            }
            try {
                Thread.sleep((int)(Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } // for        
    } //playMusicB

 

 

 

 

 

쓰레드와 상태제어

쓰레드 실행

 

 

쓰레드는 어떻게 실행될까?

쓰레드가 3개가 있다면 JVM은 시간을 잘게 쪼갠 후에 한번은 쓰레드1을, 한번은 쓰레드 2를, 한번은 쓰레드 3을 실행합니다. 이것에 빠르게 일어나다 보니 쓰레드가 모두 동작하는 것처럼 보이는 것이다.

즉 쓰레드는 실행되었다가 멈췄다가(실행 대기상태) 하는것을 반복한다.

 

쓰레드 동작

빨간줄은 deplecated된 상태.

  • 쓰레드는 실행가능상태인 Runnable실행상태인 Running상태로 나뉜다.
  • 쓰레드를 실행하면 어떤 상태가 됩니까? 하면 실행가능상태인 Runnable과 실행상태인 Running상태로 나뉜다고 해야한다
  • 실행되는 쓰레드 안에서 Thread.sleep()이나 Object가 가지고 있는 wait()메소드가 호출이 되면 쓰레드는 블록상태가 된다.
  • Thread.sleep()특정시간이 지나면 자신 스스로 블록상태에서 빠져나와 Runnable이나 Running상태가 된다.
  • Object가 가지고 있는 wait()메소드다른 쓰레드가 notify()나 notifyAll()메소드를 호출하기 전에는 블록상태에서 해제되지 않는다.
  • wait()메소드는 호출이 되면 모니터링 락을 놓게 된다. 그래서 대기중인 다른 메소드가 실행한다.
  • 쓰레드의 run메소드가 종료되면, 쓰레드는 종료된다. 즉 Dead상태가 된다.
  • Thread의 yeild메소드가 호출되면 해당 쓰레드는 다른 쓰레드에게 자원을 양보하게 된다. 즉 다른 쓰레드가 좀더    빠르게 실행되게 할 수 있다.
  • Thread가 가지고 있는 join메소드를 호출하게 되면 해당 쓰레드가 종료될 때까지 대기하게 된다.

 

 

 

 

 

쓰레드와 상태제어 join()메소드

 

join()메소드쓰레드가 멈출때까지 기다리게 한다.

  • 일단 0.5초씩 쉬면서 숫자를 출력하는 MyThread5를 작성해 보도록 하겠습니다.
    public class MyThread5 extends Thread{
        public void run(){
            for(int i = 0; i < 5; i++){
                System.out.println("MyThread5 : "+ i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } // run
    }

 

 

  • 쓰레드와 동시에 시작하는 메인쓰레드
    public class JoinExam1 { 
        public static void main(String[] args) {
            MyThread5 thread = new MyThread5();
          
            thread.start(); 
            System.out.println("시작");

            System.out.println("종료"); 
        }   
    }

main도 하나의 쓰레드고 start()한 쓰레드도 하나의 쓰레드이다. (두개의 쓰레드)

 

실행결과

시작

종료

MyThread5 : 0

MyThread5 : 1

MyThread5 : 2

MyThread5 : 3

MyThread5 : 4

 

  • 해당 쓰레드를 실행하고, 해당쓰레드가 종료될때까지 기다린 후, 내용을 출력하는 JoinExam2클래스
    public class JoinExam2 { 
        public static void main(String[] args) {
            MyThread5 thread = new MyThread5();
            // Thread 시작 
            thread.start(); 
            System.out.println("Thread가 종료될때까지 기다립니다.");
            try {
                // 해당 쓰레드가 멈출때까지 멈춤
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread가 종료되었습니다."); 
        }   
    }

 

 

실행결과

Thread가 종료될때까지 기다립니다.

MyThread5 : 0

MyThread5 : 1

MyThread5 : 2

MyThread5 : 3

MyThread5 : 4

Thread가 종료되었습니다.

 

 

 

쓰레드와 상태제어 wait(), notify()메소드

wait와 notify는 동기화된 블록안에서 사용해야 한다. wait를 만나게 되면 해당 쓰레드는

해당 객체의 모니터링 락에 대한 권한을 가지고 있다면 모니터링 락의 권한을 놓고 대기한다.

 

  • Thread를 상속받는 ThreadB클래스를 작성

일이 모두 끝나면 쓰레드를 깨울 수 있는 notify()메소드

    public class ThreadB extends Thread{
       // 해당 쓰레드가 실행되면 자기 자신의 모니터링 락을 획득
       // 5번 반복하면서 0.5초씩 쉬면서 total에 값을 누적
       // 그후에 notify()메소드를 호출하여 wiat하고 있는 쓰레드를 깨움 
        int total;
        @Override
        public void run(){
            synchronized(this){ // wait와 notify는 동기화된 블록안에서 사용해야 한다
                for(int i=0; i<5 ; i++){
                    System.out.println(i + "를 더합니다.");
                    total += i;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                notify(); // 일이 모두 끝나면 쓰레드를 깨울 수 있는 notify메소드
            }
        }
    }

 

  • 이번에는 ThreadB를 사용하며 wait하는 클래스 작성
    public class ThreadA {
        public static void main(String[] args){
            // 앞에서 만든 쓰레드 B를 만든 후 start 
            // 해당 쓰레드가 실행되면, 해당 쓰레드는 
            // run메소드 안에서 자신의 모니터링 락을 획득
            ThreadB b = new ThreadB();
            b.start();

            // b에 대하여 동기화 블럭을 설정
            // 만약 main쓰레드가 아래의 블록을 
            // 위의 Thread보다 먼저 실행되었다면 wait를 하게 되면서 모니터링 락을 놓고 대기       
            synchronized(b){
                try{
                    // b.wait()메소드를 호출.
                    // 메인쓰레드는 정지
                    // ThreadB가 5번 값을 더한 후 notify를 호출하게 되면 wait에서 깨어남
                    System.out.println("b가 완료될때까지 기다립니다.");
                    b.wait(); // 블럭안에서 b가 완료될때까지 wait를 만났으니 대기
                }catch(InterruptedException e){
                    e.printStackTrace();
                }

                //깨어난 후 결과를 출력
                System.out.println("Total is: " + b.total);
            }
        }
    }

 

 

실행결과

b가 완료될때까지 기다립니다.

0를 더합니다.

1를 더합니다.

2를 더합니다.

3를 더합니다.

4를 더합니다.

Total is: 10

 

 

 

 

 

데몬 쓰레드

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

윈도우에서는 보통 서비스라고 얘기한다.

 

데몬 쓰레드(daemon Thread)

 자바에서 데몬과 유사하게 동작하는 쓰레드

 

 

  • 데몬쓰레드를 만드는 방법은 쓰레드에 데몬 설정을 하면 된다.
    • 이런 쓰레드는 자바프로그램을 만들 때 백그라운드에서 특별한 작업을 처리하게 하는 용도로 만든다.
    • 예를 들어서 자동으로 데이터를 저장하는 쓰레드, 일정한 시간마다 맞춤법 검사를 하는 쓰레드
  • 데몬쓰레드는 일반 쓰레드(main 등)가 모두 종료되면 강제적으로 종료되는 특징을 가지고 있다.
    // Runnable을 구현하는 DaemonThread클래스를 작성
    public class DaemonThread implements Runnable {

        // 무한루프안에서 0.5초씩 쉬면서 데몬쓰레드가 실행중입니다를 출력하도록 run()메소드를 작성
        @Override
        public void run() {
            while (true) {
                System.out.println("데몬 쓰레드가 실행중입니다.");

                try {
                    Thread.sleep(500);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break; //Exception발생시 while 문 빠찌도록 
                }
            }
        }

        public static void main(String[] args) {
            // Runnable을 구현하는 DaemonThread를 실행하기 위하여 Thread 생성
            Thread th = new Thread(new DaemonThread());
            // 데몬쓰레드로 설정
            th.setDaemon(true);
            // 쓰레드를 실행
            th.start();

            // 메인 쓰레드가 1초뒤에 종료되도록 설정. 
            // 데몬쓰레드는 다른 쓰레드가 모두 종료되면 자동종료.
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }   
            System.out.println("메인 쓰레드가 종료됩니다. ");    
        }   
    }

 

 

실행결과

데몬 쓰레드가 실행중입니다.

데몬 쓰레드가 실행중입니다.

메인 쓰레드가 종료됩니다.

 

메인 쓰레드가 종료되니까 데몬 쓰레드도 같이 종료되는 모습을 볼 수 있다.

 

 

반응형