ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 멀티 스레드 - 데몬 스레드 & 스레드 그룹
    CSE/Java 2015. 12. 12. 20:25

    멀티 스레드는 여러 절로 구성되어 있습니다.

     


    Intro

    작업스레드

    스레드 우선순위 & 동기화 메소드와 동기화 블록





    데몬 스레드

     데몬(daemon) 스레드는 주 스레드의 작업을 돕는 보조적인 역할을 하는 스레드입니다. 주 스레드가 종료되면 데몬 스레드는 강제적으로 종료되는데, 그 이유는 주 스레드의 보조 역할을 수행하므로 주 스레드가 종료되면 데몬 스레드의 존재 의미가 없어지기 때문입니다.


     스레드를 데몬으로 만들기 위해서는 주 스레드가 데몬이 될 스레드의 setDaemon(true)을 호출해주면 됩니다. 아래 코드를 보면 메인 스레드가 주 스레드가 되고 AutoSaveThread가 데몬 스레드가 됩니다.




    1
    2
    3
    4
    5
    6
    7
    8
    public static void main(String[] args) {
        AutoSaveThread thread = new AutoSaveThread();
        thread.setDaemon(true);
        thread.start();
     
        ...
    }
     
    cs





     주의할 점은 start() 메소드가 호출되고 나서 setDaemon(true)를 호출하면 IllegalThreadStateException이 발생하기 때문에 start() 메소드 호출 전에 setDaemon(true)를 호출해야 합니다.


     다음 예제는 1초 주기로 save() 메소드를 자동 호출하도록 AutoSaveThread()를 작성하고, 메인 스레드가 3초 후 종료되면 AutoSaveThread도 같이 종료되도록 데몬 스레드로 만들었습니다.



     * AutoSaveThread.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    package mT;
     
    public class AutoSaveThread extends Thread {
        
        public void save() {
            System.out.println("작업 내용 저장함");
        }
        
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    break;
                }
                save();
            }
        }
        
     
    }
     
    cs





     * DaemonExam.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    package mT;
     
    public class DaemonExam {
        public static void main(String[] args) {
            AutoSaveThread asThread = new AutoSaveThread();
            asThread.setDaemon(true);
            asThread.start();
            
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {}
            
            System.out.println("메인 스레드 종료");
        }
    }
     
    cs






     











    스레드 그룹

     스레드 그룹(Thread Group)은 관련된 스레드를 묶어서 관리할 목적으로 이용합니다. JVM이 실행되면 system 스레드 그룹을 만들고, JVM 운영에 필요한 스레드들을 생성해서 system 스레드 그룹에 포함시킵니다. 그리고 system의 하위 스레드 그룹으로 main을 만들고 메인 스레드를 main 스레드 그룹에 포함시킵니다.


     스레드는 반드시 하나의 그룹에 포함되는데, 명시적으로 스레드 그룹에 포함시키지 않으면 기본적으로 자신을 생성한 스레드와 같은 그룹에 속하게 됩니다. 




     스레드 그룹 이름 얻기

      현재 스레드가 속한 스레드 그룹의 이름을 얻고 싶다면 다음과 같은 코드를 사용할 수 있습니다.


    1
    2
    3
    4
    ThreadGroup threadGroup = Thread.currentThread.getThreadGroup();
     
    String groupName = threadGroup.getName();
     
    cs




      Thread의 정적 메소드인 getAllStackTraces()를 이용하면 프로세스 내에서 실행하는 모든 스레드에 대한 정보를 얻을 수 있습니다.



    1
    2
    Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
     
    cs




      getAllStackTraces() 메소드는 Map 타입의 객체를 리턴하는데, 키는 스레드 객체이고 값은 스레드의 상태 기록들을 갖고 있는 StackTraceElement[] 배열입니다.


      다음 예제는 현재 실행하고 있는 스레드의 이름과 데몬 여부 그리고 속한 스레드 그룹 이름이 무엇인지 출력합니다.





     * ThreadInfoExam.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    package mT;
     
    import java.util.Map;
    import java.util.Set;
     
    public class ThreadInfoExam {
        public static void main(String[] args) {
            AutoSaveThread asThread = new AutoSaveThread();
            asThread.setName("AutoSaveThread");
            asThread.setDaemon(true);
            asThread.start();
     
            Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
            Set<Thread> threads = map.keySet();
     
            for (Thread thread : threads) {
                System.out.println("Name: " + thread.getName() + ((thread.isDaemon()) ? "(Daemon)" : "(Main)"));
                System.out.println("\t" + "소속그룹: " + thread.getThreadGroup().getName());
                System.out.println();
            }
        }
     
    }
     
    cs















     스레드 그룹 생성

      명시적으로 스레드 그룹을 만들고 싶다면 다음 생성자 중 하나를 이용해서 ThreadGroup 객체를 만들면 됩니다. threadGroup 이름만 주거나, 부모 ThreadGroup과 이름을 파라미터로 줄수 있습니다.



    1
    2
    ThreadGroup tg = new ThreadGroup(String name);
    ThreadGroup tg = new ThreadGroup(ThreadGroup parent, String name);
    cs




      스레드 그룹 생성 시 부모(parent) 스레드 그룹을 지정하지 않으면 현재 스레드가 속한 그룹의 하위 그룹으로 생성됩니다.


      새로운 스레드 그룹을 생성한 후, 이 그룹에 스레드를 포함시키려면 Thread 객체를 생성할 때 생성자 파라미터로 스레드 그룹을 지정하면 됩니다. 스레드 그룹을 파라미터로 갖는 Thread 생성자는 다음 네 가지가 있습니다.



    1
    2
    3
    4
    Thread t = new Thread(ThreadGroup tg, Runnable target);
    Thread t = new Thread(ThreadGroup tg, Runnable target, String name);
    Thread t = new Thread(ThreadGroup tg, Runnable target, String name, long stackSize);
    Thread t = new Thread(ThreadGroup tg, String name);
    cs




      Runnable 타입의 target은 Runnable 구현 객체를 말하며, String 타입의 name은 스레드의 이름입니다. 그리고 long 타입의 stackSize는 JVM이 이 스레드에 할당할 stack 크기입니다.








     스레드 그룹의 일괄 interrupt()

      스레드를 스레드 그룹에 포함시키면 스레드 그룹에서 제공하는 interrupt() 메소드를 이용하면 그룹 내에 포함된 모든 스레드들을 일괄 interrupt 할 수 있습니다.


      스레드 그룹의 interrupt() 메소드는 소속된 스레드의 interrupt() 메소드를 호출만 할 뿐 개별 스레드에서 발생하는 InterruptedException에 대한 예외 처리를 하지 않습니다. 따라서 안전한 종료를 위해서는 개별 스레드가 예외 처리를 해야 합니다.


      다음은 ThreadGroup이 가지고 있는 주요 메소드들입니다.



     






      다음 예제는 스레드 그룹을 생성하고, 정보를 출력해봅니다. 그리고 3초 후 스레드 그룹의 interrupt() 메소드를 호출해서 스레드 그룹에 포함된 모든 스레드들을 종료시킵니다.





     * WorkThread.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package mT;
     
    public class WorkThread extends Thread {
        public WorkThread(ThreadGroup tg, String threadName) {
            super(tg, threadName);
        }
        
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    System.out.println(getName() + " interrupted"); 
                    break;
                }
            }
            
            System.out.println(getName() + " 종료됨");
            
        }
    }
     
    cs






     * ThreadGroupExam.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    package mT;
     
    public class ThreadGroupExam {
        public static void main(String[] args) {
            ThreadGroup myGroup = new ThreadGroup("myGroup");
            WorkThread wThreadA = new WorkThread(myGroup, "wThreadA");
            WorkThread wThreadB = new WorkThread(myGroup, "wThreadB");
            
            wThreadA.start();
            wThreadB.start();
            
            System.out.println("[ main 스레드 그룹의 list() 메소드 출력 내용] ");
            ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
            mainGroup.list();
            System.out.println();
            
            try { Thread.sleep(3000); } catch (Exception e) {}
            
            System.out.println("[ myGroup 스레드 그룹의 interrupt() 메소드 호출]" );
            myGroup.interrupt();
        }
     
    }
     
    cs




     














     * 이 포스트은 서적 '이것이 자바다' 를 참고하여 작성한 포스트입니다.

    댓글

Designed by Tistory.