※ 이 코드에서 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;
publicclass WorkThread extends Thread {
public WorkThread(ThreadGroup threadGroup, String threadName) {
super(threadGroup, threadName); // 스레드 그룹과 스레드 이름을 설정
동시에 실행은 해야 하지만 공유가 되면 안 되는 동기화 프로그래밍을 해야 되는 경우가 의외로 많습니다.
제가 진행했던 개인 프로젝트 중 Java를 사용한 간단한 Hash비교 기능과 랜섬웨어에 의하여 암호화된 파일들을 복호화 해주는 백신 아닌 백신을 제작하였었는데, 당시 빠른검사, 정밀검사 기능을 제작하던 중, GUI에서 Progress Bar를 사용하여 검사 중인 파일의 경로 + 파일명, 진행상태 표시를 위한 Progress Bar 를 실행하니 실시간으로 진행되는 파일명 출력과 게이지가 차지를 않고, 검사 종료 후, 맨 마지막에 검사한 파일의 파일명만 출력되고, 게이지 또한 공백 상태에서 꽉찬 게이지 형식으로 변경이 되었었습니다.
당시 pannel thread와 검사 thread 간의 임계영역 간섭 문제였던걸로 생각이 들어서 검사 thread에 synchronized를 적용하니 정상적으로 일반 백신처럼 진행되는 것을 확인 할 수 있었습니다.
모든 상황이 저와 같지는 않으시겠지만 굉장히 다양한 경우가 많으니 검색등을 통하여 알아보시기 바랍니다!