※ 이 코드에서 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() 메소드를 호출만 할 뿐 개별 스레드에서 발생하는 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;
publicclass WorkThread extends Thread {
public WorkThread(ThreadGroup threadGroup, String threadName) {
super(threadGroup, threadName); // 스레드 그룹과 스레드 이름을 설정
part 3에서는 정지와 관련된 스레드의 안전한 종료(stop 플래그, interrupt())에 대해서 알아보도록 하겠습니다.
스레드는 자신의 run() 메소드가 모두 실행되면 자동적으로 종료 됩니다.
(저번 글(Java - 스레드 상태 제어 (Thread State Control) part1)에서 notify()와 wait()의 사용 예제를 작성해보며 run()메소드가 모두 실행이 되었음에도 불구하고, 계속 살아 있었던 경우가 있었습니다(자동적으로 종료 되지 않았습니다). 그 부분을 이번 글에서 나온 내용을 바탕으로 해결하였습니다.)
스레드 상태에 대하여 작성했던 내용 중에 stop() 메소드를 사용하면 스레드를 즉시 종료시킬 수 있다고 했었는데, 그 메소드는 deprecated 되었다고 했습니다. 그 이유는 stop() 메소드로 스레드를 갑자기 종료하게 되면 스레드가 사용 중이던 자원들이 불안전한 상태로 남겨지기 때문이라고 합니다.
stop 메소드 대신 stop 플래그를 이용하는 방법과 interrupt() 메소드를 이용하는 방법이 있습니다.
우선 stop 플래그를 이용하는 방법에 대하여 알아보겠습니다.
다음과 같이 간단하게 이해하시면 되지 않을까 싶습니다.
===============
while(조건) {
실행 문장
}
===============
위의 while 문에서 조건 부분이 참이면 실행이 되고, 거짓이면 실행이 되지 않는 점을 이용합니다.
예를들어 다음과 같이 활용할 수 있습니다.
===============
private boolean stop;
public void run() {
while ( !stop ) {
스레드가 반복 실행하는 코드;
}
//스레드가 사용한 자원 정리
}
===============
이처럼 stop이 true가 되면 while이 종료됩니다.
while을 빠져나오게 되면 스레드가 사용한 자원을 정리하게 되고, run() 메소드가 끝나게 되면서 스레드는 안전하게 종료됩니다.