[JAVA] 쓰레드 ( Thread ) ③

DongGyu Jung·2022년 3월 27일
0

자바(JAVA)

목록 보기
46/60
post-thumbnail

🏃‍♂️ 들어가기 앞서..

본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕

*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.



👍 우선순위 (priority of thread)

지금까지 배웠던 것을 돌아봤을 때,
쓰레드들의 작업순서는
" OS 스케줄러 "가 정하는 순서에 따라 번갈아가며 작업을 한다는 것을 알 수 있었다.

하지만
사용자가 의도해서

작업의 중요도에 따라
" 쓰레드 우선순위 "를 다르게 해서
특정 쓰레드가 더 많은 작업시간을 갖게 할 수 있다.

예를 들어
파일 전송 기능을 가진 메신저 프로그램에서 파일 다운로드 작업도 처리해야하지만
가장 중요한 작업은 채팅일 것이다.
따라서 채팅 내용을 전송하는 쓰레드의 우선순위를 더 높여서
비록 다운로드 작업에 소요되는 시간을 더 길어지겠지만
채팅 작업을 우선시할 수 있다.

🎯 우선순위 지정

※ 관련 메서드 & 상수

  • void setPriority( int newPriority ) : 지정한 값으로 우선순위 변경
  • int getPriority() : 우선순위 반환

  • public static final int MIN_PRIORITY = 1 : 최소 우선순위
  • public static final int NORM_PRIORITY = 5 : 일반 우선순위
  • public static final int MAX_PRIORITY = 10 : 최대 우선순위

우선순의 지정 가능 범위 = 1~10 ▶ main쓰레드의 경우 : 5 (자동)

기본적으로
JVM의 우선순위」는 위에 보이는 것 처럼
범위가 1 ~ 10으로 지정할 수 있도록 정해져있고

Windows OS의 경우」에는
우선순위 범위가 32단계로 나뉘어져 있다.

그렇기 때문에 Window OS 를 기준으로
JVM에서 설정된 쓰레드들의 우선순위를
Window OS의 "OS 스케줄러"에 전달해 서로 조율해서 작업을 처리하게 되는 것이다.

이 말은 즉슨,
우리가 쓰레드들의 우선순위를 각자 지정한다고
현재 OS 전체 작업을 다 제끼고 우선적으로 설정되는 것이 아니라
"""
내가 《작업하는 프로그램에서의 쓰레드 한정》 우선순위를 결정했으니
고려해서 작업을 처리해 달라

"""
라고 요청을 하는 것이다.

그저 "희망 사항"을 스케쥴러에 전달하는 것일 뿐이고
결국엔 이 프로그램 외 OS 내에서 돌아가는 전체 프로그램들의 작업 효율을 따져
OS 스케줄러가 순서를 정하는 것이다.



💼 쓰레드 그룹 (thread group)

" 서로 관련된 쓰레드 "를 그룹으로 묶어서 다루기 위한 것
★ 모든 쓰레드는 반드시 하나의 쓰레드 그룹에 포함되어 있어야 함.

그룹 미지정 쓰레드 ▶ "main쓰레드 그룹" 에 속함 (자동)

새로 생성된 쓰레드 》는
" 자신을 생성한 쓰레드 " ( == 부모 쓰레드 )의
그룹우선순위를 상속받는다.

Thread( ThreadGroup group, String name ) /* Thread 클래스 상속받아서 만들어진 Thread의 경우 */ 
Thread( ThreadGroup group, Runnable target ) /* Runnable 인터페이스 구현해서 만들어진 경우 */
Thread( ThreadGroup group, Runnable target, String name  )
Thread( ThreadGroup group, Runnable target, String name , long stackSize ) // + 생성할 호출스택 사이즈 설정 

상단에서 설명했듯 쓰레드 그룹을 지정하지 않고 생성해도 오류가 발생하지는 않지만
반드시 한 그룹에 포함되어 있어야하기 때문에

main 쓰레드 그룹으로 자동 소속된다고 하는데
그 이유는
" 우리가 생성하는 모든 쓰레드 그룹 "은
모두 main 쓰레드 그룹의 하위 쓰레드 그룹이기 때문에

물론 우리가 생성한 쓰레드 그룹을 설정해주면
해당 쓰레드 그룹에 소속되겠지만
지정하지 않을 경우, 자동으로 main쓰레드 그룹에 속하게 되는 것이다.

※ 관련 메서드

  • ThreadGroup getThreadGroup() : 자신이 속한 쓰레드 그룹 반환
  • void uncaughtException( Thread th, Throwable e )
    : [ 처리되지 않은 예외 ]에 의해 " 쓰레드 그룹의 쓰레드가 실행 종료 되었을 때 ", JVM에 의해 해당 메서드가 자동 호출된다.
    → 기존의 예외 처리 동작이 아닌 다른 방식의 예외 처리 동작 설정 ( printstacktrace X )

🔧 쓰레드 그룹 메서드

Method설명
[ 생성 ]
ThreadGroup( String name )지정된 이름의 새로운 쓰레드 그룹 생성
ThreadGroup( ThreadGroup parent, String name )지정된 쓰레드 그룹에 속하는
지정된 이름의 새로운 쓰레드 그룹 생성
[ 반환 ]
int activeCount()(쓰레드 그룹에 포함된) 활성상태 쓰레드 수 반환
int activeGroupCount()(쓰레드 그룹에 포함된) 활성상태 쓰레드 그룹 수 반환
int getMaxPriority()(쓰레드 그룹의) 최대 우선순위 반환
String getName()(쓰레드 그룹의) 이름 반환
ThreadGroup getParent()쓰레드 그룹의 상위 쓰레드 그룹 반환
void list()소속 쓰레드 & 하위 쓰레드 그룹 정보 " 출력 "
[ 조회 / 확인 ]
boolean isDaemon()해당 쓰레드 그룹이 데몬 쓰레드 그룹인지 확인
boolean isDestroyed()해당 쓰레드 그룹이 삭제되었는지 확인
boolean parentOf( ThreadGroup g )해당 쓰레드 그룹이
지정된 쓰레드 그룹" 의 " 상위 쓰레드 그룹인지 확인
void checkAccess()" 현재 실행 중인 쓰레드 " 가 쓰레드 그룹을 변경할 권한이 있는지 체크
[ 삭제 ]
void destroy()쓰레드 그룹 & 하위 쓰레드 그룹까지 몽땅 삭제
int enumerate( Thread[] list )
int enumerate( Thread[] list, boolean recurse )
int enumerate( ThreadGroup[] list )
int enumerate( ThreadGroup[] list, boolean recurse )
《 그룹에 속한 쓰레드 / 하위 쓰레드 그룹 》의 목록
→ 지정된 배열에 담고 개수 반환
[ 설정 ]
void setDaemon( boolean daemon )쓰레드 그룹 ▶ " 데몬 쓰레드 그룹 "으로 설정/해제
void setMaxPriority(int Priority)그룹의 최대 우선순위 설정
void interrupt()그룹에 속한 모든 쓰레드를 interrupt : 재실행



🎈 데몬 쓰레드 (daemon thread)

다른 " 일반 쓰레드 (non-daemon thread) "의 작업을 돕는 보조적인 역할을 수행하는 쓰레드

다른 쓰레드의 작업이 끝나지 않으면 프로그램이 종료되지 않는
일반 쓰레드와는 달리

데몬 쓰레드(daemon thread)는 일반 쓰레드가 모두 종료되면
강제적으로 자동 종료된다.
( 보조적인 역할이다 보니 일반 쓰레드가 종료되면 존재의 의미가 없어지기 때문이다. )

자동 종료되는 특징을 제외하고는
일반 쓰레드와 다를 것 없다.

《 데몬 쓰레드로 처리하는 작업의 예 》
: 메인 작업에 수행 중에만 필요한 관련 서브 기능들
가비지 컬렉터 (Garbage Collector)
자동 저장
* 화면 자동 갱신
* ...

데몬 쓰레드는
" 무한 루프(Loop) "" 조건문 "을 활용해서 작성하는데
이는
우선 계속 실행 유지하고 특정 조건 만족 시에 작업을 수행되도록 하기 위해서이다.
( 메인 일반 쓰레드의 작업이 언제 끝날지 모르니까 while문으로 계속 유지시켜 놓는 것 )

public void run() {
	while (true) {
    	try {
        	Thread.sleep(3*1000); // 3초 대기 → 3초"마다"
        } catch (InterruptedException e) { } // 작업 중단 예외 발생 대비
        
        // 가정 : autoSave는 자동 저장 메서드
        if (autoSave) autoSave(); //autoSave 값이 true면 메서드 호출
        
        /* 위 과정 루프 */
    }
}

데몬 쓰레드를 작성하는 것은
일반 쓰레드와 별반 다를 것 없고

한가지 , 생성 후
실행( start() )하기 setDaemon( true )를 호출하기만 하면 된다.
( 안하면 IllegalThreadStateException 발생 )

class DaemonPractice implements Runnable { // Runnable 인터페이스 구현 방식
	static boolean autoSave = false ; // 초기값 : false
    
    public static void main(String[] args) {
    	Thread t = new Thread( new DaemonPractice() ) ;
        t.setDaemon( true ) ; // 실행 전에 무조건 실행시켜줘야함.
        t.start();
        
        /* 시작하는 순간부터 이미 데몬 쓰레드는 실행되고 있는 것 _ 단, 아직 조건문 실행이 안되는 것 뿐 */
        for ( int i = 0 ; i <= 10 ; i++ ) {
        	try{
            	Thread.sleep(1000); 
            } catch(InterruptedException e) {}
            System.out.println(i);
            
            // 5초 경과되었을 때부터 autoSave  true로 바뀌고 내부 조건문 실행되기 시작함
            if (i == 5) autoSave = true; 
        }
        System.out.println("프로그램 종료")
    }
    
    public void run() { //run() 구현
    	/* start하는 순간 계속 while문은 실행되고 있음 */
        while(true) {
        	try {
        	Thread.sleep(3*1000); 
        	} catch (InterruptedException e) { } 
            
            // true 값이 들어와야 실행되기 시작되는 점 유의
	        if (autoSave) autoSave(); // 실행 조건
        }
    }
    
    public void autoSave() {
    	System.out.println("자동 저장");
    }       
}

/*
<출력>
1
2
3
4
5
6
자동저장
7
8
자동저장
9
10
프로그램 종료 ▶ 일반 쓰레드(main 쓰레드)의 작업이 종료되었기 때문에 데몬 쓰레드 자동 종료
*/

0개의 댓글