이번에는 스레드 그룹에 대하여 알아 보도록 하겠습니다.

 

스레드 그룹의 정의는 다음과 같이 되어 있습니다.

 

- 스레드 그룹(ThreadGroup)은 관련된 스레드를 묶어서 관리할 목적으로 이용된다.

 

추가적인 설명은 다음과 같습니다.

 

JVM이 실행되면 system 스레드 그룹을 만들고, JVM 운영에 필요한 스레드들을 생성해서 system 스레드 그룹에 포함시킵니다.

system의 하위 스레드 그룹으로 main을 만들고 메인 스레드를 main 스레드 그룹에 포함시킵니다.

스레드는 반드시 하나의 스레드 그룹에 포함됩니다.

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

우리가 생성하는 작업 스레드는 대부분 main 스레드가 생성하므로 기본적으로 main 스레드가 생성하므로 기본적으로 main 스레드 그룹에 속하게 됩니다.

 

※ 추가 설명에서 main 스레드 또한 사용자가 직접 생성하기 때문에 유저 스레드라고 생각합니다.

ex) public static void main(String[] args) {}

 


스레드를 그룹 지정하여 관리하게 되면 여러가지 편할 것 같습니다(현업에서 많이 사용할지는 아직 잘 모르겠습니다.)

 

스레드 그룹이 있을 경우 관리를 위해 그룹 이름을 알아야 하지요!

그에 따른 스레드 그룹 이름 얻기.

 

스레드 그룹을 만들지도 않았는데 관리는 무슨!

스레드 그룹 생성.

 

다 사용 했으면 자원 돌려줘야지!

스레드 그룹의 일괄 interrupt().

 

이렇게 3가지에 대하여 알아 보도록 하겠습니다.

 


스레드 그룹의 이름을 얻기 위해서는 getName() 메소드를 이용하여 확인할 수 있습니다.

 

 

다음 예제를 통하여 알아 보도록 하겠습니다.

 

 

 

 

ThreadInfoExample.java - 현재 실행 중인 스레드 정보

package thread_group;
 
 
public class ThreadInfoExample {
 
    public static void main(String[] args) {
        AutoSaveThread autoSaveThread = new AutoSaveThread();
        autoSaveThread.setName("AutoSaveThread");
        autoSaveThread.setDaemon(true);
        autoSaveThread.start();
        
        Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
        Set<Thread> threads = map.keySet();
        for(Thread thread : threads) {
            System.out.println("Name: " + thread.getName() +
                    ((thread.isDaemon())?"(데몬)""(주)"));
            System.out.println("\t" + "소속그룹: " + thread.getThreadGroup().getName());
            System.out.println();
        }
    }
}

※ 이 코드에서 AutoSaveThread 클래스는 제 이전 글인 데몬 스레드 글에서 확인 하실 수 있습니다.

    또는 이것이 자바다 교재를 확인하시거나 이것이 자바다 교재에서 제공하는 예제코드를 활용하시기 바랍니다.

 

 

이 코드를 실행하시게 되면 다음과 같은 결과를 확인할 수 있습니다.

 

Name: AutoSaveThread(데몬)

소속그룹: main

 

Name: Reference Handler(데몬)

소속그룹: system

 

Name: Signal Dispatcher(데몬)

소속그룹: system

 

Name: main(주)

소속그룹: main

 

Name: Finalizer(데몬)

소속그룹: system

 


스레드 그룹 생성은 간단하게 생성 방법에 대해서만 알아보고, 스레드 그룹의 일괄 interrupt()에서 사용하며 익숙해지도록 하겠습니다.

 

스레드 그룹 생성은 다음과 같이 할 수 있습니다.

 


ThreadGroup tg = new ThreadGroup(String name);

ThreadGroup tg = new ThreadGroup(ThreadGroup parent, String name);


Thread t = new Thread(ThreadGroup group, Runnable target);

Thread t = new Thread(ThreadGroup group, Runnable target, String name);

Thread t = new Thread(ThreadGroup group, Runnable target, String name, long stackSize);

Thread t = new Thread(ThreadGroup group, String name);


이 6가지를 통해서 알 수 있는 것은 다음과 같습니다.

 

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

ex) main 스레드가 ThreadGroup(String name)을 이용해 새로운 스레드 그룹 생성시, main 스레드 그룹의 하위 스레드 그룹이 됩니다.

- Runnable 타입의 target은 Runnable 구현 객체를 말합니다.

- String 타입의 name은 스레드의 이름입니다.

- long 타입의 stackSize는 JVM이 이 스레드에 할당할 stack 크기입니다.

 


스레드 그룹의 일괄 interrupt()

 

스레드 그룹을 생성하게 될 경우의 편리성! 이라 할 수 있는게 대표적으로 스레드 종료가 있습니다.

스레드 그룹을 지정하지 않고, interrupt() 하게 될 경우, 스레드마다 interrupt()를 작성해 줘야 합니다.

하지만! 스레드 그룹을 지정해서 관리할 경우, 같은 스레드 그룹에 소속되어 있을 경우 스레드 그룹의 interrupt() 메소드를 한 번만 호출해주면 됩니다.

interrupt()를 작성하지도 않았는데 이것이 가능한 이유는 스레드 그룹의 interrupt() 메소드는 포함된 모든 스레드의 interrupt() 메소드를 내부적으로 호출해주기 때문입니다.

 

글이 아닌 [그림]으로 조금 더 직관적으로 알아 보도록 하겠습니다.

 

[그림 - 스레드 그룹의 일괄 interrupt()]

또한 다음과 같은 점도 있습니다.

 

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

 

스레드 그룹에도 interrupt() 메소드 이외에 suspend(), resume(), stop() 메소드들이 있는데, 모두 Deprecated 되었습니다.

 

다음 표는 Thread Group이 가지고 있는 주요 메소드들입니다.

 

메소드 설명
int activeCount() 현재 그룹 및 하위 그룹에서 활동 중인 모든 스레드의 수를 리턴한다.
int activeGroupCount() 현재 그룹에서 활동 중인 모든 하위 그룹의 수를 리턴한다.
void checkAccess() 현재 스레드가 스레드 그룹을 변경할 권한이 있는지 체크한다. 만약 권한이 없으면 SecurityException을 발생시킨다.
void destroy() 현재 그룹 및 하위 그룹을 모두 삭제한다. 단, 그룹 내에 포함된 모든 스레드들이 종료 상태가 되어야 한다.
boolean isDestroyed() 현재 그룹이 삭제되었는지 여부를 리턴한다.
int getMaxPriority() 현재 그룹에 포함된 스레드가 가질 수 있는 최대 우선순위를 리턴한다.
void setMaxPriority(int pri) 현재 그룹에 포함된 스레드가 가질 수 있는 최대 우선순위를 설정한다.
String getName() 현재 그룹의 이름을 리턴한다.
ThreadGroup getParent() 현재 그룹의 부모 그룹을 리턴한다.
boolean parentOf(ThreadGroup g) 현재 그룹이 매개값으로 지정한 스레드 그룹의 부모인지 여부를 리턴한다.
boolean isDaemon() 현재 그룹이 데몬 그룹인지 여부를 리턴한다.
void setDaemon(boolean daemon) 현재 그룹을 데몬 그룹으로 설정한다.
void list() 현재 그룹에 포함된 스레드와 하위 그룹에 대한 정보를 출력한다.
void interrupt() 현재 그룹에 포함된 모든 스레드들을 interrupt한다.

 

많습니다...

다 외우시거나 외우고 계시는 분들이 많을 것 같습니다만, 저는 필요할 때마다 찾아서 사용하고 많이 사용하면서 익숙해지도록 해야겠네요.

 

이제 예제를 통하여 스레드 그룹의 interrupt()를 해보도록 하겠습니다.

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

 

 

 

 

WorkThread.java - InterruptedException이 발생할 때 스레드가 종료되도록 함

package thread_group_create;
 
public class WorkThread extends Thread {
 
    public WorkThread(ThreadGroup threadGroup, String threadName) {
        super(threadGroup, threadName);    // 스레드 그룹과 스레드 이름을 설정
    }
    
    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                /*
                    InterruptedException이 발생될 때,
                    while문을 빠져나와 스레드를 종료시킵니다.
                */
                System.out.println(getName() + " interrupted");
                break;
            }
        }
        System.out.println(getName() + " 종료됨");
    }
}

 

 

 

 

ThreadGroupExample.java - 스레드 그룹을 이용한 일괄 종료 예제

package thread_group_create;
 
public class ThreadGroupExample {
 
    public static void main(String[] args) {
        //    myGroup에 두 스레드를 포함시킵니다.
        ThreadGroup myGroup = new ThreadGroup("myGroup");
        WorkThread workThreadA = new WorkThread(myGroup, "workThreadA");
        WorkThread workThreadB = new WorkThread(myGroup, "workThreadB");
        
        workThreadA.start();
        workThreadB.start();
        
        System.out.println("[ main 스레드 그룹의 list() 메소드 출력 내용 ]");
        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
        mainGroup.list();
        System.out.println();
        
        try { Thread.sleep(3000); } catch (InterruptedException e) {}
        
        System.out.println("[ myGroup 스레드 그룹의 interrupt() 메소드 호출 ]");
        myGroup.interrupt();
    }
}

 

 

이 예제를 실행할 경우 다음과 같은 결과를 확인할 수 있습니다.

 

[ main 스레드 그룹의 list() 메소드 출력 내용 ]

java.lang.ThreadGroup[name=main,maxpri=10]

    Thread[main,5,main]

    java.lang.ThreadGroup[name=myGroup,maxpri=10]

        Thread[workThreadA,5,myGroup]

        Thread[workThreadB,5,myGroup]

 

[ myGroup 스레드 그룹의 interrupt() 메소드 호출 ]

workThreadB interrupted

workThreadB 종료됨

workThreadA interrupted

workThreadA 종료됨

 

※ myGroup 스레드 그룹의 interrupt() 메소드 호출의 결과는 매 실행시 출력 순서가 달라질 수 있습니다.

 

 

ThreadGroupExample.java의 mainGroup.list() 에서 list() 메소드는 현재 스레드 그룹의 이름과 최대 우선순위를 헤더로 출력하고, 그 아래에 현재 스레드 그룹에 포함된 스레드와 하위 스레드 그룹의 내용을 보여줍니다.

스레드의 경우 [스레드 이름, 우선순위, 소속 그룹명]으로 출력되는 것을 확인할 수 있습니다.

 

또한 interrupt() 메소드를 호출하면 myGroup에 포함된 두 스레드에서 InterruptedException이 발생되어 스레드가 종료되는 것을 알 수 있습니다.

 

 

+ Recent posts